diff options
Diffstat (limited to 'Source')
412 files changed, 17018 insertions, 7904 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index b1f7b29..24370aa 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -134,6 +134,9 @@ set(SRCS LexerParser/cmFortranParser.cxx LexerParser/cmFortranParserTokens.h LexerParser/cmFortranParser.y + LexerParser/cmGccDepfileLexer.cxx + LexerParser/cmGccDepfileLexer.h + LexerParser/cmGccDepfileLexer.in.l LexerParser/cmListFileLexer.c LexerParser/cmListFileLexer.in.l @@ -270,6 +273,10 @@ set(SRCS cmFortranParserImpl.cxx cmFSPermissions.cxx cmFSPermissions.h + cmGccDepfileLexerHelper.cxx + cmGccDepfileLexerHelper.h + cmGccDepfileReader.cxx + cmGccDepfileReader.h cmGeneratedFileStream.cxx cmGeneratorExpressionContext.cxx cmGeneratorExpressionContext.h @@ -289,6 +296,8 @@ set(SRCS cmGeneratorExpression.h cmGeneratorTarget.cxx cmGeneratorTarget.h + cmLinkItemGraphVisitor.cxx + cmLinkItemGraphVisitor.h cmGetPipes.cxx cmGetPipes.h cmGlobalCommonGenerator.cxx @@ -475,6 +484,8 @@ set(SRCS cmBuildCommand.h cmBuildNameCommand.cxx cmBuildNameCommand.h + cmCMakeCommand.cxx + cmCMakeCommand.h cmCMakeHostSystemInformationCommand.cxx cmCMakeHostSystemInformationCommand.h cmCMakeMinimumRequired.cxx @@ -691,6 +702,8 @@ set(SRCS cmDuration.h cmDuration.cxx + + bindexplib.cxx ) SET_PROPERTY(SOURCE cmProcessOutput.cxx APPEND PROPERTY COMPILE_DEFINITIONS @@ -713,7 +726,6 @@ if (WIN32) set(SRCS ${SRCS} cmCallVisualStudioMacro.cxx cmCallVisualStudioMacro.h - bindexplib.cxx ) if(NOT UNIX) @@ -1193,6 +1205,11 @@ if(WIN32) endforeach() endif() +if(CMake_JOB_POOL_LINK_BIN) + set_property(TARGET ${_tools} PROPERTY JOB_POOL_LINK "link-bin") + set_property(GLOBAL APPEND PROPERTY JOB_POOLS "link-bin=${CMake_JOB_POOL_LINK_BIN}") +endif() + # Install tools foreach(_tool ${_tools}) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 6a8d2fc..e87ad32 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 16) -set(CMake_VERSION_PATCH 5) +set(CMake_VERSION_MINOR 17) +set(CMake_VERSION_PATCH 20200312) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CPack/OSXScriptLauncher.cxx b/Source/CPack/OSXScriptLauncher.cxx index 21d27a0..bdaf779 100644 --- a/Source/CPack/OSXScriptLauncher.cxx +++ b/Source/CPack/OSXScriptLauncher.cxx @@ -5,6 +5,8 @@ #include <string> #include <vector> +#include <cm/memory> + #include <CoreFoundation/CoreFoundation.h> #include "cmsys/FStream.hxx" @@ -26,7 +28,6 @@ int main(int argc, char* argv[]) CFStringRef fileName; CFBundleRef appBundle; CFURLRef scriptFileURL; - UInt8* path; // get CF URL for script if (!(appBundle = CFBundleGetMainBundle())) { @@ -41,13 +42,15 @@ int main(int argc, char* argv[]) } // create path string - if (!(path = new UInt8[PATH_MAX])) { + auto path = cm::make_unique<UInt8[]>(PATH_MAX); + if (!path) { return 1; } // get the file system path of the url as a cstring // in an encoding suitable for posix apis - if (!CFURLGetFileSystemRepresentation(scriptFileURL, true, path, PATH_MAX)) { + if (!CFURLGetFileSystemRepresentation(scriptFileURL, true, path.get(), + PATH_MAX)) { DebugError("CFURLGetFileSystemRepresentation failed"); return 1; } @@ -55,10 +58,10 @@ int main(int argc, char* argv[]) // dispose of the CF variable CFRelease(scriptFileURL); - std::string fullScriptPath = reinterpret_cast<char*>(path); - delete[] path; + std::string fullScriptPath = reinterpret_cast<char*>(path.get()); + path.reset(); - if (!cmsys::SystemTools::FileExists(fullScriptPath.c_str())) { + if (!cmsys::SystemTools::FileExists(fullScriptPath)) { return 1; } @@ -80,7 +83,6 @@ int main(int argc, char* argv[]) cmsysProcess_SetTimeout(cp, 0); cmsysProcess_Execute(cp); - std::vector<char> tempOutput; char* data; int length; while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) { diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index e71a38f..67d3d32 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -4,6 +4,7 @@ #include <algorithm> +#include <cm/memory> #include <cm/string_view> #include "cmsys/Directory.hxx" @@ -35,22 +36,16 @@ #include "cmCMakeToWixPath.h" cmCPackWIXGenerator::cmCPackWIXGenerator() - : Patch(0) - , ComponentGuidType(cmWIXSourceWriter::WIX_GENERATED_GUID) + : ComponentGuidType(cmWIXSourceWriter::WIX_GENERATED_GUID) { } -cmCPackWIXGenerator::~cmCPackWIXGenerator() -{ - if (this->Patch) { - delete this->Patch; - } -} +cmCPackWIXGenerator::~cmCPackWIXGenerator() = default; int cmCPackWIXGenerator::InitializeInternal() { componentPackageMethod = ONE_PACKAGE; - this->Patch = new cmWIXPatch(this->Logger); + this->Patch = cm::make_unique<cmWIXPatch>(this->Logger); return this->Superclass::InitializeInternal(); } diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h index d193348..d5a16ec 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.h +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -4,6 +4,7 @@ #define cmCPackWIXGenerator_h #include <map> +#include <memory> #include <string> #include "cmCPackGenerator.h" @@ -24,6 +25,8 @@ public: cmCPackTypeMacro(cmCPackWIXGenerator, cmCPackGenerator); cmCPackWIXGenerator(); + cmCPackWIXGenerator(const cmCPackWIXGenerator&) = delete; + const cmCPackWIXGenerator& operator=(const cmCPackWIXGenerator&) = delete; ~cmCPackWIXGenerator(); protected: @@ -157,7 +160,7 @@ private: std::string CPackTopLevel; - cmWIXPatch* Patch; + std::unique_ptr<cmWIXPatch> Patch; cmWIXSourceWriter::GuidType ComponentGuidType; }; diff --git a/Source/CPack/WiX/cmWIXPatch.cxx b/Source/CPack/WiX/cmWIXPatch.cxx index ca232f9..122ffaf 100644 --- a/Source/CPack/WiX/cmWIXPatch.cxx +++ b/Source/CPack/WiX/cmWIXPatch.cxx @@ -41,7 +41,7 @@ void cmWIXPatch::ApplyFragment(std::string const& id, void cmWIXPatch::ApplyElementChildren(const cmWIXPatchElement& element, cmWIXSourceWriter& writer) { - for (cmWIXPatchNode* node : element.children) { + for (const auto& node : element.children) { switch (node->type()) { case cmWIXPatchNode::ELEMENT: ApplyElement(dynamic_cast<const cmWIXPatchElement&>(*node), writer); diff --git a/Source/CPack/WiX/cmWIXPatchParser.cxx b/Source/CPack/WiX/cmWIXPatchParser.cxx index fd9103b..5588d2d 100644 --- a/Source/CPack/WiX/cmWIXPatchParser.cxx +++ b/Source/CPack/WiX/cmWIXPatchParser.cxx @@ -2,6 +2,10 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmWIXPatchParser.h" +#include <utility> + +#include <cm/memory> + #include "cm_expat.h" #include "cmCPackGenerator.h" @@ -20,12 +24,8 @@ cmWIXPatchNode::~cmWIXPatchNode() { } -cmWIXPatchElement::~cmWIXPatchElement() -{ - for (cmWIXPatchNode* child : children) { - delete child; - } -} +cmWIXPatchElement::cmWIXPatchElement() = default; +cmWIXPatchElement::~cmWIXPatchElement() = default; cmWIXPatchParser::cmWIXPatchParser(fragment_map_t& fragments, cmCPackLog* logger) @@ -54,8 +54,7 @@ void cmWIXPatchParser::StartElement(const std::string& name, const char** atts) } else if (State == INSIDE_FRAGMENT) { cmWIXPatchElement& parent = *ElementStack.back(); - cmWIXPatchElement* element = new cmWIXPatchElement; - parent.children.push_back(element); + auto element = cm::make_unique<cmWIXPatchElement>(); element->name = name; @@ -66,7 +65,8 @@ void cmWIXPatchParser::StartElement(const std::string& name, const char** atts) element->attributes[key] = value; } - ElementStack.push_back(element); + ElementStack.push_back(element.get()); + parent.children.push_back(std::move(element)); } } @@ -130,10 +130,10 @@ void cmWIXPatchParser::CharacterDataHandler(const char* data, int length) std::string::size_type last = text.find_last_not_of(whitespace); if (first != std::string::npos && last != std::string::npos) { - cmWIXPatchText* text_node = new cmWIXPatchText; + auto text_node = cm::make_unique<cmWIXPatchText>(); text_node->text = text.substr(first, last - first + 1); - parent.children.push_back(text_node); + parent.children.push_back(std::move(text_node)); } } } diff --git a/Source/CPack/WiX/cmWIXPatchParser.h b/Source/CPack/WiX/cmWIXPatchParser.h index 87dd892..8d5d2ad 100644 --- a/Source/CPack/WiX/cmWIXPatchParser.h +++ b/Source/CPack/WiX/cmWIXPatchParser.h @@ -4,6 +4,7 @@ #define cmCPackWIXPatchParser_h #include <map> +#include <memory> #include <vector> #include "cmCPackLog.h" @@ -33,9 +34,14 @@ struct cmWIXPatchElement : cmWIXPatchNode { virtual Type type(); + cmWIXPatchElement(); + + cmWIXPatchElement(const cmWIXPatchElement&) = delete; + const cmWIXPatchElement& operator=(const cmWIXPatchElement&) = delete; + ~cmWIXPatchElement(); - using child_list_t = std::vector<cmWIXPatchNode*>; + using child_list_t = std::vector<std::unique_ptr<cmWIXPatchNode>>; using attributes_t = std::map<std::string, std::string>; std::string name; diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx index ea71007..fe7abf4 100644 --- a/Source/CPack/cmCPackDragNDropGenerator.cxx +++ b/Source/CPack/cmCPackDragNDropGenerator.cxx @@ -138,11 +138,16 @@ int cmCPackDragNDropGenerator::InitializeInternal() } for (auto const& language : languages) { std::string license = slaDirectory + "/" + language + ".license.txt"; - if (!singleLicense && !cmSystemTools::FileExists(license)) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Missing license file " << language << ".license.txt" - << std::endl); - return 0; + std::string license_rtf = slaDirectory + "/" + language + ".license.rtf"; + if (!singleLicense) { + if (!cmSystemTools::FileExists(license) && + !cmSystemTools::FileExists(license_rtf)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Missing license file " + << language << ".license.txt" + << " / " << language << ".license.rtf" << std::endl); + return 0; + } } std::string menu = slaDirectory + "/" + language + ".menu.txt"; if (!cmSystemTools::FileExists(menu)) { @@ -775,6 +780,11 @@ std::string cmCPackDragNDropGenerator::GetComponentInstallDirNameSuffix( } } + std::string componentFileName = + "CPACK_DMG_" + cmSystemTools::UpperCase(componentName) + "_FILE_NAME"; + if (this->IsSet(componentFileName)) { + return this->GetOption(componentFileName); + } return GetComponentPackageFileName(package_file_name, componentName, false); } @@ -788,13 +798,29 @@ bool cmCPackDragNDropGenerator::WriteLicense( licenseLanguage = "English"; } + // License file + std::string license_format = "TEXT"; + std::string actual_license; + if (!licenseFile.empty()) { + if (cmHasLiteralSuffix(licenseFile, ".rtf")) { + license_format = "RTF "; + } + actual_license = licenseFile; + } else { + std::string license_wo_ext = + slaDirectory + "/" + licenseLanguage + ".license"; + if (cmSystemTools::FileExists(license_wo_ext + ".txt")) { + actual_license = license_wo_ext + ".txt"; + } else { + license_format = "RTF "; + actual_license = license_wo_ext + ".rtf"; + } + } + // License header - outputStream << "data 'TEXT' (" << licenseNumber << ", \"" << licenseLanguage - << "\") {\n"; + outputStream << "data '" << license_format << "' (" << licenseNumber + << ", \"" << licenseLanguage << "\") {\n"; // License body - std::string actual_license = !licenseFile.empty() - ? licenseFile - : (slaDirectory + "/" + licenseLanguage + ".license.txt"); cmsys::ifstream license_ifs; license_ifs.open(actual_license.c_str()); if (license_ifs.is_open()) { @@ -873,8 +899,9 @@ bool cmCPackDragNDropGenerator::BreakLongLine(const std::string& line, std::string* error) { const size_t max_line_length = 512; - for (size_t i = 0; i < line.size(); i += max_line_length) { - size_t line_length = max_line_length; + size_t line_length = max_line_length; + for (size_t i = 0; i < line.size(); i += line_length) { + line_length = max_line_length; if (i + line_length > line.size()) { line_length = line.size() - i; } else { diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index 6698f3c..712eb77 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -621,9 +621,9 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( buildConfigs.emplace_back(); } - std::unique_ptr<cmGlobalGenerator> globalGenerator( + std::unique_ptr<cmGlobalGenerator> globalGenerator = this->MakefileMap->GetCMakeInstance()->CreateGlobalGenerator( - cmakeGenerator)); + cmakeGenerator); if (!globalGenerator) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Specified package generator not found. " diff --git a/Source/CPack/cmCPackLog.cxx b/Source/CPack/cmCPackLog.cxx index ca675fd..49e4113 100644 --- a/Source/CPack/cmCPackLog.cxx +++ b/Source/CPack/cmCPackLog.cxx @@ -4,54 +4,38 @@ #include <iostream> +#include <cm/memory> + #include "cmGeneratedFileStream.h" #include "cmSystemTools.h" cmCPackLog::cmCPackLog() { - this->Verbose = false; - this->Debug = false; - this->Quiet = false; - this->NewLine = true; - - this->LastTag = cmCPackLog::NOTAG; this->DefaultOutput = &std::cout; this->DefaultError = &std::cerr; - - this->LogOutput = nullptr; - this->LogOutputCleanup = false; } -cmCPackLog::~cmCPackLog() -{ - this->SetLogOutputStream(nullptr); -} +cmCPackLog::~cmCPackLog() = default; void cmCPackLog::SetLogOutputStream(std::ostream* os) { - if (this->LogOutputCleanup && this->LogOutput) { - delete this->LogOutput; - } - this->LogOutputCleanup = false; + this->LogOutputStream.reset(); this->LogOutput = os; } bool cmCPackLog::SetLogOutputFile(const char* fname) { - cmGeneratedFileStream* cg = nullptr; + this->LogOutputStream.reset(); if (fname) { - cg = new cmGeneratedFileStream(fname); - } - if (cg && !*cg) { - delete cg; - cg = nullptr; + this->LogOutputStream = cm::make_unique<cmGeneratedFileStream>(fname); } - this->SetLogOutputStream(cg); - if (!cg) { - return false; + if (this->LogOutputStream && !*this->LogOutputStream) { + this->LogOutputStream.reset(); } - this->LogOutputCleanup = true; - return true; + + this->LogOutput = this->LogOutputStream.get(); + + return this->LogOutput != nullptr; } void cmCPackLog::Log(int tag, const char* file, int line, const char* msg, diff --git a/Source/CPack/cmCPackLog.h b/Source/CPack/cmCPackLog.h index 1cb1643..68ffcce 100644 --- a/Source/CPack/cmCPackLog.h +++ b/Source/CPack/cmCPackLog.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <memory> #include <ostream> #include <string> @@ -97,13 +98,13 @@ public: void SetErrorPrefix(std::string const& pfx) { this->ErrorPrefix = pfx; } private: - bool Verbose; - bool Debug; - bool Quiet; + bool Verbose = false; + bool Debug = false; + bool Quiet = false; - bool NewLine; + bool NewLine = true; - int LastTag; + int LastTag = cmCPackLog::NOTAG; std::string Prefix; std::string OutputPrefix; @@ -112,13 +113,11 @@ private: std::string WarningPrefix; std::string ErrorPrefix; - std::ostream* DefaultOutput; - std::ostream* DefaultError; + std::ostream* DefaultOutput = nullptr; + std::ostream* DefaultError = nullptr; - std::string LogOutputFileName; - std::ostream* LogOutput; - // Do we need to cleanup log output stream - bool LogOutputCleanup; + std::ostream* LogOutput = nullptr; + std::unique_ptr<std::ostream> LogOutputStream; }; class cmCPackLogWrite diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx index 9bf72df..363f536 100644 --- a/Source/CPack/cmCPackNSISGenerator.cxx +++ b/Source/CPack/cmCPackNSISGenerator.cxx @@ -128,22 +128,26 @@ int cmCPackNSISGenerator::PackageFiles() this->IsSet("CPACK_NSIS_MUI_UNIICON")) { std::string installerIconCode; if (this->IsSet("CPACK_NSIS_MUI_ICON")) { - installerIconCode += "!define MUI_ICON \""; - installerIconCode += this->GetOption("CPACK_NSIS_MUI_ICON"); - installerIconCode += "\"\n"; + installerIconCode += cmStrCat( + "!define MUI_ICON \"", this->GetOption("CPACK_NSIS_MUI_ICON"), "\"\n"); } if (this->IsSet("CPACK_NSIS_MUI_UNIICON")) { - installerIconCode += "!define MUI_UNICON \""; - installerIconCode += this->GetOption("CPACK_NSIS_MUI_UNIICON"); - installerIconCode += "\"\n"; + installerIconCode += + cmStrCat("!define MUI_UNICON \"", + this->GetOption("CPACK_NSIS_MUI_UNIICON"), "\"\n"); } this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_ICON_CODE", installerIconCode.c_str()); } - if (this->IsSet("CPACK_PACKAGE_ICON")) { - std::string installerIconCode = - cmStrCat("!define MUI_HEADERIMAGE_BITMAP \"", - this->GetOption("CPACK_PACKAGE_ICON"), "\"\n"); + std::string installerHeaderImage; + if (this->IsSet("CPACK_NSIS_MUI_HEADERIMAGE")) { + installerHeaderImage = this->GetOption("CPACK_NSIS_MUI_HEADERIMAGE"); + } else if (this->IsSet("CPACK_PACKAGE_ICON")) { + installerHeaderImage = this->GetOption("CPACK_PACKAGE_ICON"); + } + if (!installerHeaderImage.empty()) { + std::string installerIconCode = cmStrCat( + "!define MUI_HEADERIMAGE_BITMAP \"", installerHeaderImage, "\"\n"); this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_ICON_CODE", installerIconCode.c_str()); } @@ -173,6 +177,32 @@ int cmCPackNSISGenerator::PackageFiles() installerRunCode.c_str()); } + if (this->IsSet("CPACK_NSIS_WELCOME_TITLE")) { + std::string welcomeTitleCode = + cmStrCat("!define MUI_WELCOMEPAGE_TITLE \"", + this->GetOption("CPACK_NSIS_WELCOME_TITLE"), "\""); + this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_WELCOME_TITLE_CODE", + welcomeTitleCode.c_str()); + } + + if (this->IsSet("CPACK_NSIS_WELCOME_TITLE_3LINES")) { + this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_WELCOME_TITLE_3LINES_CODE", + "!define MUI_WELCOMEPAGE_TITLE_3LINES"); + } + + if (this->IsSet("CPACK_NSIS_FINISH_TITLE")) { + std::string finishTitleCode = + cmStrCat("!define MUI_FINISHPAGE_TITLE \"", + this->GetOption("CPACK_NSIS_FINISH_TITLE"), "\""); + this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_FINISH_TITLE_CODE", + finishTitleCode.c_str()); + } + + if (this->IsSet("CPACK_NSIS_FINISH_TITLE_3LINES")) { + this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_FINISH_TITLE_3LINES_CODE", + "!define MUI_FINISHPAGE_TITLE_3LINES"); + } + // Setup all of the component sections if (this->Components.empty()) { this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES", ""); diff --git a/Source/CPack/cmCPackOSXX11Generator.cxx b/Source/CPack/cmCPackOSXX11Generator.cxx index 951c65f..5de4a6f 100644 --- a/Source/CPack/cmCPackOSXX11Generator.cxx +++ b/Source/CPack/cmCPackOSXX11Generator.cxx @@ -178,6 +178,9 @@ int cmCPackOSXX11Generator::PackageFiles() int cmCPackOSXX11Generator::InitializeInternal() { + cmCPackLogger(cmCPackLog::LOG_WARNING, + "The OSXX11 generator is deprecated " + "and will be removed in a future version.\n"); cmCPackLogger(cmCPackLog::LOG_DEBUG, "cmCPackOSXX11Generator::Initialize()" << std::endl); std::vector<std::string> path; diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx index dae5ec9..ac3d64d 100644 --- a/Source/CPack/cmCPackPKGGenerator.cxx +++ b/Source/CPack/cmCPackPKGGenerator.cxx @@ -46,7 +46,66 @@ std::string cmCPackPKGGenerator::GetPackageName( return component.ArchiveFile + ".pkg"; } -void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile) +void cmCPackPKGGenerator::CreateBackground(const char* themeName, + const char* metapackageFile, + cm::string_view genName, + cmXMLWriter& xout) +{ + std::string paramSuffix = + (themeName == nullptr) ? "" : cmSystemTools::UpperCase(themeName); + std::string opt = (themeName == nullptr) + ? cmStrCat("CPACK_", genName, "_BACKGROUND") + : cmStrCat("CPACK_", genName, "_BACKGROUND_", paramSuffix); + const char* bgFileName = this->GetOption(opt); + if (bgFileName == nullptr) { + return; + } + + std::string bgFilePath = cmStrCat(metapackageFile, "/Contents/", bgFileName); + + if (!cmSystemTools::FileExists(bgFilePath)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Background image doesn't exist in the resource directory: " + << bgFileName << std::endl); + return; + } + + if (themeName == nullptr) { + xout.StartElement("background"); + } else { + xout.StartElement(cmStrCat("background-", themeName)); + } + + xout.Attribute("file", bgFileName); + + const char* param = this->GetOption(cmStrCat(opt, "_ALIGNMENT")); + if (param != nullptr) { + xout.Attribute("alignment", param); + } + + param = this->GetOption(cmStrCat(opt, "_SCALING")); + if (param != nullptr) { + xout.Attribute("scaling", param); + } + + // Apple docs say that you must provide either mime-type or uti + // attribute for the background, but I've seen examples that + // doesn't have them, so don't make them mandatory. + param = this->GetOption(cmStrCat(opt, "_MIME_TYPE")); + if (param != nullptr) { + xout.Attribute("mime-type", param); + } + + param = this->GetOption(cmStrCat(opt, "_UTI")); + if (param != nullptr) { + xout.Attribute("uti", param); + } + + xout.EndElement(); +} + +void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile, + const char* genName) { std::string distributionTemplate = this->FindTemplate("CPack.distribution.dist.in"); @@ -102,6 +161,11 @@ void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile) CreateChoice(PostFlightComponent, xout); } + // default background + this->CreateBackground(nullptr, metapackageFile, genName, xout); + // Dark Aqua + this->CreateBackground("darkAqua", metapackageFile, genName, xout); + this->SetOption("CPACK_PACKAGEMAKER_CHOICES", choiceOut.str().c_str()); // Create the distribution.dist file in the metapackage to turn it diff --git a/Source/CPack/cmCPackPKGGenerator.h b/Source/CPack/cmCPackPKGGenerator.h index 69286ff..be730ab 100644 --- a/Source/CPack/cmCPackPKGGenerator.h +++ b/Source/CPack/cmCPackPKGGenerator.h @@ -9,6 +9,8 @@ #include <sstream> #include <string> +#include <cm/string_view> + #include "cmCPackComponentGroup.h" #include "cmCPackGenerator.h" @@ -57,7 +59,7 @@ protected: // inter-component dependencies. metapackageFile is the name of the // metapackage for the distribution. Only valid for a // component-based install. - void WriteDistributionFile(const char* metapackageFile); + void WriteDistributionFile(const char* metapackageFile, const char* genName); // Subroutine of WriteDistributionFile that writes out the // dependency attributes for inter-component dependencies. @@ -85,6 +87,10 @@ protected: /// installer GUI. void CreateChoice(const cmCPackComponent& component, cmXMLWriter& xout); + /// Creates a background in the distribution XML. + void CreateBackground(const char* themeName, const char* metapackageFile, + cm::string_view genName, cmXMLWriter& xout); + // The PostFlight component when creating a metapackage cmCPackComponent PostFlightComponent; }; diff --git a/Source/CPack/cmCPackPackageMakerGenerator.cxx b/Source/CPack/cmCPackPackageMakerGenerator.cxx index c5ba726..f51ea42 100644 --- a/Source/CPack/cmCPackPackageMakerGenerator.cxx +++ b/Source/CPack/cmCPackPackageMakerGenerator.cxx @@ -279,7 +279,7 @@ int cmCPackPackageMakerGenerator::PackageFiles() } else { // We have built the package in place. Generate the // distribution.dist file to describe it for the installer. - WriteDistributionFile(packageDirFileName.c_str()); + WriteDistributionFile(packageDirFileName.c_str(), "PACKAGEMAKER"); } std::string tmpFile = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), @@ -321,6 +321,9 @@ int cmCPackPackageMakerGenerator::PackageFiles() int cmCPackPackageMakerGenerator::InitializeInternal() { + cmCPackLogger(cmCPackLog::LOG_WARNING, + "The PackageMaker generator is deprecated " + "and will be removed in a future version.\n"); this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr"); // Starting with Xcode 4.3, PackageMaker is a separate app, and you diff --git a/Source/CPack/cmCPackProductBuildGenerator.cxx b/Source/CPack/cmCPackProductBuildGenerator.cxx index dae268c..a3e55de 100644 --- a/Source/CPack/cmCPackProductBuildGenerator.cxx +++ b/Source/CPack/cmCPackProductBuildGenerator.cxx @@ -81,7 +81,7 @@ int cmCPackProductBuildGenerator::PackageFiles() } // combine package(s) into a distribution - WriteDistributionFile(packageDirFileName.c_str()); + WriteDistributionFile(packageDirFileName.c_str(), "PRODUCTBUILD"); std::ostringstream pkgCmd; std::string version = this->GetOption("CPACK_PACKAGE_VERSION"); diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx index 5895652..dc31623 100644 --- a/Source/CPack/cpack.cxx +++ b/Source/CPack/cpack.cxx @@ -115,7 +115,6 @@ int main(int argc, char const* const* argv) argc = args.argc(); argv = args.argv(); - cmSystemTools::EnableMSVCDebugHook(); cmSystemTools::InitializeLibUV(); cmSystemTools::FindCMakeResources(argv[0]); cmCPackLog log; @@ -314,7 +313,7 @@ int main(int argc, char const* const* argv) else { // get a default value (current working directory) cpackProjectDirectory = cmsys::SystemTools::GetCurrentWorkingDirectory(); - // use default value iff no value has been provided by the config file + // use default value if no value has been provided by the config file if (!globalMF.IsSet("CPACK_PACKAGE_DIRECTORY")) { globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY", cpackProjectDirectory); @@ -324,6 +323,12 @@ int main(int argc, char const* const* argv) globalMF.AddDefinition(cd.first, cd.second); } + // Force CPACK_PACKAGE_DIRECTORY as absolute path + cpackProjectDirectory = globalMF.GetDefinition("CPACK_PACKAGE_DIRECTORY"); + cpackProjectDirectory = + cmSystemTools::CollapseFullPath(cpackProjectDirectory); + globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY", cpackProjectDirectory); + const char* cpackModulesPath = globalMF.GetDefinition("CPACK_MODULE_PATH"); if (cpackModulesPath) { globalMF.AddDefinition("CMAKE_MODULE_PATH", cpackModulesPath); diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx index 8640c46..c87fb83b 100644 --- a/Source/CTest/cmCTestBZR.cxx +++ b/Source/CTest/cmCTestBZR.cxx @@ -8,11 +8,12 @@ #include <ostream> #include <vector> +#include <cmext/algorithm> + #include "cmsys/RegularExpression.hxx" #include "cm_expat.h" -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestVC.h" #include "cmProcessTools.h" @@ -245,7 +246,7 @@ private: void CharacterDataHandler(const char* data, int length) override { - cmAppend(this->CData, data, data + length); + cm::append(this->CData, data, data + length); } void EndElement(const std::string& name) override diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index 2ad661c..5e29386 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -215,11 +215,11 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) if (this->BuildNoCMake) { // Make the generator available for the Build call below. - cmGlobalGenerator* gen = cm.CreateGlobalGenerator(this->BuildGenerator); - cm.SetGlobalGenerator(gen); + cm.SetGlobalGenerator(cm.CreateGlobalGenerator(this->BuildGenerator)); if (!this->BuildGeneratorPlatform.empty()) { - cmMakefile mf(gen, cm.GetCurrentSnapshot()); - if (!gen->SetGeneratorPlatform(this->BuildGeneratorPlatform, &mf)) { + cmMakefile mf(cm.GetGlobalGenerator(), cm.GetCurrentSnapshot()); + if (!cm.GetGlobalGenerator()->SetGeneratorPlatform( + this->BuildGeneratorPlatform, &mf)) { return 1; } } diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx index 18df214..d1b7701 100644 --- a/Source/CTest/cmCTestBuildCommand.cxx +++ b/Source/CTest/cmCTestBuildCommand.cxx @@ -29,13 +29,7 @@ void cmCTestBuildCommand::BindArguments() this->Bind("PROJECT_NAME"_s, this->ProjectName); } -cmCTestBuildCommand::~cmCTestBuildCommand() -{ - if (this->GlobalGenerator) { - delete this->GlobalGenerator; - this->GlobalGenerator = nullptr; - } -} +cmCTestBuildCommand::~cmCTestBuildCommand() = default; cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() { @@ -79,8 +73,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() } if (this->GlobalGenerator) { if (this->GlobalGenerator->GetName() != cmakeGeneratorName) { - delete this->GlobalGenerator; - this->GlobalGenerator = nullptr; + this->GlobalGenerator.reset(); } } if (!this->GlobalGenerator) { diff --git a/Source/CTest/cmCTestBuildCommand.h b/Source/CTest/cmCTestBuildCommand.h index da00a43..0f82817 100644 --- a/Source/CTest/cmCTestBuildCommand.h +++ b/Source/CTest/cmCTestBuildCommand.h @@ -48,7 +48,7 @@ public: bool InitialPass(std::vector<std::string> const& args, cmExecutionStatus& status) override; - cmGlobalGenerator* GlobalGenerator = nullptr; + std::unique_ptr<cmGlobalGenerator> GlobalGenerator; protected: cmCTestBuildHandler* Handler; diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index 9cb5449..03a3fd3 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -7,11 +7,12 @@ #include <set> #include <utility> +#include <cmext/algorithm> + #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" #include "cmsys/Process.h" -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmDuration.h" #include "cmFileTimeCache.h" @@ -969,7 +970,7 @@ void cmCTestBuildHandler::ProcessBuffer(const char* data, size_t length, if (it != queue->end()) { // Create a contiguous array for the line this->CurrentProcessingLine.clear(); - cmAppend(this->CurrentProcessingLine, queue->begin(), it); + cm::append(this->CurrentProcessingLine, queue->begin(), it); this->CurrentProcessingLine.push_back(0); const char* line = this->CurrentProcessingLine.data(); diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx index f2f42b4..3854710 100644 --- a/Source/CTest/cmCTestConfigureCommand.cxx +++ b/Source/CTest/cmCTestConfigureCommand.cxx @@ -69,12 +69,11 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() bool multiConfig = false; bool cmakeBuildTypeInOptions = false; - cmGlobalGenerator* gg = - this->Makefile->GetCMakeInstance()->CreateGlobalGenerator( - cmakeGeneratorName); + auto gg = this->Makefile->GetCMakeInstance()->CreateGlobalGenerator( + cmakeGeneratorName); if (gg) { multiConfig = gg->IsMultiConfig(); - delete gg; + gg.reset(); } std::string cmakeConfigureCommand = diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 4cd783f..2c8f119 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -12,12 +12,13 @@ #include <sstream> #include <utility> +#include <cmext/algorithm> + #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" #include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmDuration.h" #include "cmGeneratedFileStream.h" @@ -819,7 +820,7 @@ int cmCTestCoverageHandler::HandleJacocoCoverage( std::string binaryDir = this->CTest->GetCTestConfiguration("BuildDirectory"); std::string binCoverageFile = binaryDir + "/*jacoco.xml"; g2.FindFiles(binCoverageFile); - cmAppend(files, g2.GetFiles()); + cm::append(files, g2.GetFiles()); if (!files.empty()) { cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, @@ -1462,7 +1463,7 @@ int cmCTestCoverageHandler::HandleLCovCoverage( " looking for LCOV files in: " << daGlob << std::endl, this->Quiet); gl.FindFiles(daGlob); // Keep a list of all LCOV files - cmAppend(lcovFiles, gl.GetFiles()); + cm::append(lcovFiles, gl.GetFiles()); for (std::string const& file : lcovFiles) { lcovFile = file; @@ -1599,10 +1600,10 @@ void cmCTestCoverageHandler::FindGCovFiles(std::vector<std::string>& files) " globbing for coverage in: " << lm.first << std::endl, this->Quiet); std::string daGlob = cmStrCat(lm.first, "/*.da"); gl.FindFiles(daGlob); - cmAppend(files, gl.GetFiles()); + cm::append(files, gl.GetFiles()); daGlob = cmStrCat(lm.first, "/*.gcda"); gl.FindFiles(daGlob); - cmAppend(files, gl.GetFiles()); + cm::append(files, gl.GetFiles()); } } @@ -1638,7 +1639,7 @@ bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files) "Error while finding files matching " << daGlob << std::endl); return false; } - cmAppend(files, gl.GetFiles()); + cm::append(files, gl.GetFiles()); cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Now searching in: " << daGlob << std::endl, this->Quiet); return true; diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx index ccac832..69c5793 100644 --- a/Source/CTest/cmCTestCurl.cxx +++ b/Source/CTest/cmCTestCurl.cxx @@ -5,7 +5,8 @@ #include <cstdio> #include <ostream> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmCTest.h" #include "cmCurl.h" #include "cmStringAlgorithms.h" @@ -46,15 +47,15 @@ size_t curlWriteMemoryCallback(void* ptr, size_t size, size_t nmemb, { int realsize = static_cast<int>(size * nmemb); const char* chPtr = static_cast<char*>(ptr); - cmAppend(*static_cast<std::vector<char>*>(data), chPtr, chPtr + realsize); + cm::append(*static_cast<std::vector<char>*>(data), chPtr, chPtr + realsize); return realsize; } size_t curlDebugCallback(CURL* /*unused*/, curl_infotype /*unused*/, char* chPtr, size_t size, void* data) { - cmAppend(*static_cast<std::vector<char>*>(data), chPtr, chPtr + size); - return size; + cm::append(*static_cast<std::vector<char>*>(data), chPtr, chPtr + size); + return 0; } } diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx index 3265498..5f4581e 100644 --- a/Source/CTest/cmCTestHG.cxx +++ b/Source/CTest/cmCTestHG.cxx @@ -5,9 +5,10 @@ #include <ostream> #include <vector> +#include <cmext/algorithm> + #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestVC.h" #include "cmProcessTools.h" @@ -204,7 +205,7 @@ private: void CharacterDataHandler(const char* data, int length) override { - cmAppend(this->CData, data, data + length); + cm::append(this->CData, data, data + length); } void EndElement(const std::string& name) override diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index a5ec1ae..c1ecaf1 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -2,9 +2,11 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestMemCheckHandler.h" +#include <algorithm> #include <chrono> #include <cstring> #include <iostream> +#include <iterator> #include <sstream> #include <utility> @@ -12,6 +14,7 @@ #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" +#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmDuration.h" #include "cmSystemTools.h" @@ -162,12 +165,13 @@ int cmCTestMemCheckHandler::PostProcessHandler() void cmCTestMemCheckHandler::GenerateTestCommand( std::vector<std::string>& args, int test) { - std::string index; - std::ostringstream stream; + std::string index = std::to_string(test); std::string memcheckcommand = cmSystemTools::ConvertToOutputPath(this->MemoryTester); - stream << test; - index = stream.str(); + + std::vector<std::string> dirs; + bool nextArgIsDir = false; + for (std::string arg : this->MemoryTesterDynamicOptions) { std::string::size_type pos = arg.find("??"); if (pos != std::string::npos) { @@ -177,6 +181,16 @@ void cmCTestMemCheckHandler::GenerateTestCommand( memcheckcommand += " \""; memcheckcommand += arg; memcheckcommand += "\""; + + if (nextArgIsDir) { + nextArgIsDir = false; + dirs.push_back(arg); + } + + if (this->MemoryTesterStyle == cmCTestMemCheckHandler::DRMEMORY && + (arg == "-logdir" || arg == "-symcache_dir")) { + nextArgIsDir = true; + } } // Create a copy of the memory tester environment variable. // This is used for memory testing programs that pass options @@ -208,6 +222,11 @@ void cmCTestMemCheckHandler::GenerateTestCommand( memcheckcommand += " " + memTesterEnvironmentVariable; args.push_back(memTesterEnvironmentVariable); } + + for (std::string const& dir : dirs) { + cmSystemTools::MakeDirectory(dir); + } + cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Memory check command: " << memcheckcommand << std::endl, this->Quiet); @@ -300,6 +319,9 @@ void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml) case cmCTestMemCheckHandler::VALGRIND: xml.Attribute("Checker", "Valgrind"); break; + case cmCTestMemCheckHandler::DRMEMORY: + xml.Attribute("Checker", "DrMemory"); + break; case cmCTestMemCheckHandler::PURIFY: xml.Attribute("Checker", "Purify"); break; @@ -387,11 +409,11 @@ void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml) } cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "MemCheck log files can be found here: " - "( * corresponds to test number)" + "(<#> corresponds to test number)" << std::endl, this->Quiet); std::string output = this->MemoryTesterOutputFile; - cmSystemTools::ReplaceString(output, "??", "*"); + cmSystemTools::ReplaceString(output, "??", "<#>"); cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, output << std::endl, this->Quiet); cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, @@ -437,6 +459,10 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() if (testerName.find("valgrind") != std::string::npos || this->CTest->GetCTestConfiguration("MemoryCheckType") == "Valgrind") { this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND; + } else if (testerName.find("drmemory") != std::string::npos || + this->CTest->GetCTestConfiguration("MemoryCheckType") == + "DrMemory") { + this->MemoryTesterStyle = cmCTestMemCheckHandler::DRMEMORY; } else if (testerName.find("purify") != std::string::npos) { this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY; } else if (testerName.find("BC") != std::string::npos) { @@ -453,6 +479,10 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() this->MemoryTester = this->CTest->GetCTestConfiguration("ValgrindCommand"); this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND; } else if (cmSystemTools::FileExists( + this->CTest->GetCTestConfiguration("DrMemoryCommand"))) { + this->MemoryTester = this->CTest->GetCTestConfiguration("DrMemoryCommand"); + this->MemoryTesterStyle = cmCTestMemCheckHandler::DRMEMORY; + } else if (cmSystemTools::FileExists( this->CTest->GetCTestConfiguration("BoundsCheckerCommand"))) { this->MemoryTester = this->CTest->GetCTestConfiguration("BoundsCheckerCommand"); @@ -498,6 +528,8 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER; } else if (checkType == "Valgrind") { this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND; + } else if (checkType == "DrMemory") { + this->MemoryTesterStyle = cmCTestMemCheckHandler::DRMEMORY; } } if (this->MemoryTester.empty()) { @@ -519,6 +551,10 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() .empty()) { memoryTesterOptions = this->CTest->GetCTestConfiguration("ValgrindCommandOptions"); + } else if (!this->CTest->GetCTestConfiguration("DrMemoryCommandOptions") + .empty()) { + memoryTesterOptions = + this->CTest->GetCTestConfiguration("DrMemoryCommandOptions"); } this->MemoryTesterOptions = cmSystemTools::ParseArguments(memoryTesterOptions); @@ -554,6 +590,64 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() this->MemoryTesterOutputFile); break; } + case cmCTestMemCheckHandler::DRMEMORY: { + std::string tempDrMemoryDir = + this->CTest->GetBinaryDir() + "/Testing/Temporary/DrMemory"; + + if (!cmContains(this->MemoryTesterOptions, "-quiet")) { + this->MemoryTesterOptions.emplace_back("-quiet"); + } + + if (!cmContains(this->MemoryTesterOptions, "-batch")) { + this->MemoryTesterOptions.emplace_back("-batch"); + } + + this->MemoryTesterDynamicOptions.emplace_back("-logdir"); + auto logdirOption = + std::find(this->MemoryTesterOptions.begin(), + this->MemoryTesterOptions.end(), "-logdir"); + if (logdirOption == this->MemoryTesterOptions.end()) { + // No logdir found in memory tester options + std::string drMemoryLogDir = tempDrMemoryDir + "/??"; + this->MemoryTesterDynamicOptions.push_back(drMemoryLogDir); + this->MemoryTesterOutputFile = drMemoryLogDir; + } else { + // Use logdir found in memory tester options + auto logdirLocation = std::next(logdirOption); + this->MemoryTesterOutputFile = *logdirLocation; + this->MemoryTesterDynamicOptions.push_back(*logdirLocation); + this->MemoryTesterOptions.erase(logdirOption, logdirLocation + 1); + } + this->MemoryTesterOutputFile += "/*/results.txt"; + + if (std::find(this->MemoryTesterOptions.begin(), + this->MemoryTesterOptions.end(), + "-symcache_dir") == this->MemoryTesterOptions.end()) { + this->MemoryTesterDynamicOptions.emplace_back("-symcache_dir"); + std::string drMemoryCacheDir = tempDrMemoryDir + "/cache"; + this->MemoryTesterDynamicOptions.push_back(drMemoryCacheDir); + } + + if (!this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile") + .empty()) { + if (!cmSystemTools::FileExists(this->CTest->GetCTestConfiguration( + "MemoryCheckSuppressionFile"))) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Cannot find memory checker suppression file: " + << this->CTest->GetCTestConfiguration( + "MemoryCheckSuppressionFile") + << std::endl); + return false; + } + this->MemoryTesterOptions.emplace_back("-suppress"); + this->MemoryTesterOptions.push_back( + this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")); + } + + this->MemoryTesterOptions.emplace_back("--"); + + break; + } case cmCTestMemCheckHandler::PURIFY: { std::string outputFile; #ifdef _WIN32 @@ -667,6 +761,8 @@ bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str, switch (this->MemoryTesterStyle) { case cmCTestMemCheckHandler::VALGRIND: return this->ProcessMemCheckValgrindOutput(str, log, results); + case cmCTestMemCheckHandler::DRMEMORY: + return this->ProcessMemCheckDrMemoryOutput(str, log, results); case cmCTestMemCheckHandler::PURIFY: return this->ProcessMemCheckPurifyOutput(str, log, results); case cmCTestMemCheckHandler::ADDRESS_SANITIZER: @@ -932,6 +1028,47 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput( return defects == 0; } +bool cmCTestMemCheckHandler::ProcessMemCheckDrMemoryOutput( + const std::string& str, std::string& log, std::vector<int>& results) +{ + std::vector<std::string> lines; + cmsys::SystemTools::Split(str, lines); + + cmsys::RegularExpression drMemoryError("^Error #[0-9]+"); + + cmsys::RegularExpression unaddressableAccess("UNADDRESSABLE ACCESS"); + cmsys::RegularExpression uninitializedRead("UNINITIALIZED READ"); + cmsys::RegularExpression invalidHeapArgument("INVALID HEAP ARGUMENT"); + cmsys::RegularExpression leak("LEAK"); + cmsys::RegularExpression handleLeak("HANDLE LEAK"); + + int defects = 0; + + std::ostringstream ostr; + for (const auto& l : lines) { + ostr << l << std::endl; + if (drMemoryError.find(l)) { + defects++; + if (unaddressableAccess.find(l)) { + results[cmCTestMemCheckHandler::UMR]++; + } else if (uninitializedRead.find(l)) { + results[cmCTestMemCheckHandler::UMR]++; + } else if (leak.find(l)) { + results[cmCTestMemCheckHandler::MLK]++; + } else if (handleLeak.find(l)) { + results[cmCTestMemCheckHandler::MLK]++; + } else if (invalidHeapArgument.find(l)) { + results[cmCTestMemCheckHandler::FMM]++; + } + } + } + + log = ostr.str(); + + this->DefectCount += defects; + return defects == 0; +} + bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput( const std::string& str, std::string& log, std::vector<int>& results) { @@ -991,6 +1128,8 @@ void cmCTestMemCheckHandler::PostProcessTest(cmCTestTestResult& res, int test) this->Quiet); if (this->MemoryTesterStyle == cmCTestMemCheckHandler::BOUNDS_CHECKER) { this->PostProcessBoundsCheckerTest(res, test); + } else if (this->MemoryTesterStyle == cmCTestMemCheckHandler::DRMEMORY) { + this->PostProcessDrMemoryTest(res, test); } else { std::vector<std::string> files; this->TestOutputFileNames(test, files); @@ -1045,6 +1184,37 @@ void cmCTestMemCheckHandler::PostProcessBoundsCheckerTest( this->Quiet); } +void cmCTestMemCheckHandler::PostProcessDrMemoryTest( + cmCTestTestHandler::cmCTestTestResult& res, int test) +{ + std::string drMemoryLogDir = this->MemoryTesterOutputFile.substr( + 0, this->MemoryTesterOutputFile.find("/*/results.txt")); + + // replace placeholder of test + std::string::size_type pos = drMemoryLogDir.find("??"); + if (pos != std::string::npos) { + drMemoryLogDir.replace(pos, 2, std::to_string(test)); + } + + cmsys::Glob g; + g.FindFiles(drMemoryLogDir + "/resfile.*"); + const std::vector<std::string>& files = g.GetFiles(); + + for (const std::string& f : files) { + cmsys::ifstream ifs(f.c_str()); + if (!ifs) { + std::string log = "Cannot read memory tester output file: " + f; + cmCTestLog(this->CTest, ERROR_MESSAGE, log << std::endl); + return; + } + std::string resultFileLocation; + cmSystemTools::GetLineFromStream(ifs, resultFileLocation); + this->AppendMemTesterOutput(res, resultFileLocation); + ifs.close(); + cmSystemTools::RemoveFile(f); + } +} + void cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res, std::string const& ofile) { diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h index eda65f7..52667f8 100644 --- a/Source/CTest/cmCTestMemCheckHandler.h +++ b/Source/CTest/cmCTestMemCheckHandler.h @@ -43,6 +43,7 @@ private: UNKNOWN = 0, VALGRIND, PURIFY, + DRMEMORY, BOUNDS_CHECKER, // checkers after here do not use the standard error list ADDRESS_SANITIZER, @@ -132,6 +133,8 @@ private: std::vector<int>& results); bool ProcessMemCheckValgrindOutput(const std::string& str, std::string& log, std::vector<int>& results); + bool ProcessMemCheckDrMemoryOutput(const std::string& str, std::string& log, + std::vector<int>& results); bool ProcessMemCheckPurifyOutput(const std::string& str, std::string& log, std::vector<int>& results); bool ProcessMemCheckSanitizerOutput(const std::string& str, std::string& log, @@ -142,6 +145,7 @@ private: void PostProcessTest(cmCTestTestResult& res, int test); void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test); + void PostProcessDrMemoryTest(cmCTestTestResult& res, int test); //! append MemoryTesterOutputFile to the test log void AppendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res, diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 02d396e..50c963d 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -12,13 +12,15 @@ #include <iomanip> #include <iostream> #include <list> -#include <memory> #include <sstream> #include <stack> #include <unordered_map> #include <utility> #include <vector> +#include <cm/memory> +#include <cmext/algorithm> + #include "cmsys/FStream.hxx" #include "cmsys/SystemInformation.hxx" @@ -170,10 +172,11 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) this->EraseTest(test); this->RunningCount += GetProcessorsUsed(test); - cmCTestRunTest* testRun = new cmCTestRunTest(*this); - if (this->CTest->GetRepeatUntilFail()) { - testRun->SetRunUntilFailOn(); - testRun->SetNumberOfRuns(this->CTest->GetTestRepeat()); + auto testRun = cm::make_unique<cmCTestRunTest>(*this); + + if (this->RepeatMode != cmCTest::Repeat::Never) { + testRun->SetRepeatMode(this->RepeatMode); + testRun->SetNumberOfRuns(this->RepeatCount); } testRun->SetIndex(test); testRun->SetTestProperties(this->Properties[test]); @@ -194,28 +197,58 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) // working directory because FinishTestProcess() will try to unlock them this->LockResources(test); - if (!this->TestsHaveSufficientResources[test]) { - testRun->StartFailure("Insufficient resources"); - this->FinishTestProcess(testRun, false); + if (!this->ResourceAllocationErrors[test].empty()) { + std::ostringstream e; + e << "Insufficient resources for test " << this->Properties[test]->Name + << ":\n\n"; + for (auto const& it : this->ResourceAllocationErrors[test]) { + switch (it.second) { + case ResourceAllocationError::NoResourceType: + e << " Test requested resources of type '" << it.first + << "' which does not exist\n"; + break; + + case ResourceAllocationError::InsufficientResources: + e << " Test requested resources of type '" << it.first + << "' in the following amounts:\n"; + for (auto const& group : this->Properties[test]->ResourceGroups) { + for (auto const& requirement : group) { + if (requirement.ResourceType == it.first) { + e << " " << requirement.SlotsNeeded + << (requirement.SlotsNeeded == 1 ? " slot\n" : " slots\n"); + } + } + } + e << " but only the following units were available:\n"; + for (auto const& res : + this->ResourceAllocator.GetResources().at(it.first)) { + e << " '" << res.first << "': " << res.second.Total + << (res.second.Total == 1 ? " slot\n" : " slots\n"); + } + break; + } + e << "\n"; + } + e << "Resource spec file:\n\n " << this->TestHandler->ResourceSpecFile; + cmCTestRunTest::StartFailure(std::move(testRun), e.str(), + "Insufficient resources"); return false; } cmWorkingDirectory workdir(this->Properties[test]->Directory); if (workdir.Failed()) { - testRun->StartFailure("Failed to change working directory to " + - this->Properties[test]->Directory + " : " + - std::strerror(workdir.GetLastResult())); - } else { - if (testRun->StartTest(this->Completed, this->Total)) { - // Ownership of 'testRun' has moved to another structure. - // When the test finishes, FinishTestProcess will be called. - return true; - } + cmCTestRunTest::StartFailure(std::move(testRun), + "Failed to change working directory to " + + this->Properties[test]->Directory + " : " + + std::strerror(workdir.GetLastResult()), + "Failed to change working directory"); + return false; } - // Pass ownership of 'testRun'. - this->FinishTestProcess(testRun, false); - return false; + // Ownership of 'testRun' has moved to another structure. + // When the test finishes, FinishTestProcess will be called. + return cmCTestRunTest::StartTest(std::move(testRun), this->Completed, + this->Total); } bool cmCTestMultiProcessHandler::AllocateResources(int index) @@ -247,7 +280,8 @@ bool cmCTestMultiProcessHandler::AllocateResources(int index) bool cmCTestMultiProcessHandler::TryAllocateResources( int index, - std::map<std::string, std::vector<cmCTestBinPackerAllocation>>& allocations) + std::map<std::string, std::vector<cmCTestBinPackerAllocation>>& allocations, + std::map<std::string, ResourceAllocationError>* errors) { allocations.clear(); @@ -262,18 +296,28 @@ bool cmCTestMultiProcessHandler::TryAllocateResources( ++processIndex; } + bool result = true; auto const& availableResources = this->ResourceAllocator.GetResources(); for (auto& it : allocations) { if (!availableResources.count(it.first)) { - return false; - } - if (!cmAllocateCTestResourcesRoundRobin(availableResources.at(it.first), - it.second)) { - return false; + if (errors) { + (*errors)[it.first] = ResourceAllocationError::NoResourceType; + result = false; + } else { + return false; + } + } else if (!cmAllocateCTestResourcesRoundRobin( + availableResources.at(it.first), it.second)) { + if (errors) { + (*errors)[it.first] = ResourceAllocationError::InsufficientResources; + result = false; + } else { + return false; + } } } - return true; + return result; } void cmCTestMultiProcessHandler::DeallocateResources(int index) @@ -314,11 +358,13 @@ bool cmCTestMultiProcessHandler::AllResourcesAvailable() void cmCTestMultiProcessHandler::CheckResourcesAvailable() { - for (auto test : this->SortedTests) { - std::map<std::string, std::vector<cmCTestBinPackerAllocation>> allocations; - this->TestsHaveSufficientResources[test] = - !this->TestHandler->UseResourceSpec || - this->TryAllocateResources(test, allocations); + if (this->TestHandler->UseResourceSpec) { + for (auto test : this->SortedTests) { + std::map<std::string, std::vector<cmCTestBinPackerAllocation>> + allocations; + this->TryAllocateResources(test, allocations, + &this->ResourceAllocationErrors[test]); + } } } @@ -405,7 +451,7 @@ bool cmCTestMultiProcessHandler::StartTest(int test) } // Allocate resources - if (this->TestsHaveSufficientResources[test] && + if (this->ResourceAllocationErrors[test].empty() && !this->AllocateResources(test)) { this->DeallocateResources(test); return false; @@ -492,7 +538,8 @@ void cmCTestMultiProcessHandler::StartNextTests() if (this->SerialTestRunning) { break; } - // We can only start a RUN_SERIAL test if no other tests are also running. + // We can only start a RUN_SERIAL test if no other tests are also + // running. if (this->Properties[test]->RunSerial && this->RunningCount > 0) { continue; } @@ -570,8 +617,8 @@ void cmCTestMultiProcessHandler::OnTestLoadRetryCB(uv_timer_t* timer) self->StartNextTests(); } -void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner, - bool started) +void cmCTestMultiProcessHandler::FinishTestProcess( + std::unique_ptr<cmCTestRunTest> runner, bool started) { this->Completed++; @@ -583,7 +630,8 @@ void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner, this->SetStopTimePassed(); } if (started) { - if (!this->StopTimePassed && runner->StartAgain(this->Completed)) { + if (!this->StopTimePassed && + cmCTestRunTest::StartAgain(std::move(runner), this->Completed)) { this->Completed--; // remove the completed test because run again return; } @@ -611,7 +659,7 @@ void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner, } properties->Affinity.clear(); - delete runner; + runner.reset(); if (started) { this->StartNextTests(); } @@ -788,7 +836,7 @@ void cmCTestMultiProcessHandler::CreateParallelTestCostList() // Sort tests within each level by COST and append them to the cost list. for (TestSet const& currentSet : cmReverseRange(priorityStack)) { TestList sortedCopy; - cmAppend(sortedCopy, currentSet); + cm::append(sortedCopy, currentSet); std::stable_sort(sortedCopy.begin(), sortedCopy.end(), TestComparator(this)); @@ -1154,7 +1202,7 @@ static Json::Value DumpCTestInfo( const std::vector<std::string>& args = testRun.GetArguments(); if (!args.empty()) { commandAndArgs.reserve(args.size() + 1); - cmAppend(commandAndArgs, args); + cm::append(commandAndArgs, args); } testInfo["command"] = DumpToJsonArray(commandAndArgs); } diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index 1db4bfd..c3686bc 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <map> +#include <memory> #include <set> #include <string> #include <vector> @@ -14,11 +15,11 @@ #include "cm_uv.h" +#include "cmCTest.h" #include "cmCTestResourceAllocator.h" #include "cmCTestTestHandler.h" #include "cmUVHandlePtr.h" -class cmCTest; struct cmCTestBinPackerAllocation; class cmCTestResourceSpec; class cmCTestRunTest; @@ -85,6 +86,12 @@ public: cmCTestTestHandler* GetTestHandler() { return this->TestHandler; } + void SetRepeatMode(cmCTest::Repeat mode, int count) + { + this->RepeatMode = mode; + this->RepeatCount = count; + } + void SetQuiet(bool b) { this->Quiet = b; } void InitResourceAllocator(const cmCTestResourceSpec& spec) @@ -118,7 +125,7 @@ protected: // Removes the checkpoint file void MarkFinished(); void EraseTest(int index); - void FinishTestProcess(cmCTestRunTest* runner, bool started); + void FinishTestProcess(std::unique_ptr<cmCTestRunTest> runner, bool started); static void OnTestLoadRetryCB(uv_timer_t* timer); @@ -137,11 +144,18 @@ protected: void LockResources(int index); void UnlockResources(int index); + enum class ResourceAllocationError + { + NoResourceType, + InsufficientResources, + }; + bool AllocateResources(int index); bool TryAllocateResources( int index, std::map<std::string, std::vector<cmCTestBinPackerAllocation>>& - allocations); + allocations, + std::map<std::string, ResourceAllocationError>* errors = nullptr); void DeallocateResources(int index); bool AllResourcesAvailable(); @@ -168,7 +182,8 @@ protected: std::map<int, std::vector<std::map<std::string, std::vector<ResourceAllocation>>>> AllocatedResources; - std::map<int, bool> TestsHaveSufficientResources; + std::map<int, std::map<std::string, ResourceAllocationError>> + ResourceAllocationErrors; cmCTestResourceAllocator ResourceAllocator; std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults; size_t ParallelLevel; // max number of process that can be run at once @@ -179,6 +194,8 @@ protected: cmCTestTestHandler* TestHandler; cmCTest* CTest; bool HasCycles; + cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never; + int RepeatCount = 1; bool Quiet; bool SerialTestRunning; }; diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx index e2063e1..1375be4 100644 --- a/Source/CTest/cmCTestP4.cxx +++ b/Source/CTest/cmCTestP4.cxx @@ -7,9 +7,10 @@ #include <ostream> #include <utility> +#include <cmext/algorithm> + #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestVC.h" #include "cmProcessTools.h" @@ -326,7 +327,7 @@ void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions) // The CTEST_P4_OPTIONS variable adds additional Perforce command line // options before the main command std::string opts = this->CTest->GetCTestConfiguration("P4Options"); - cmAppend(P4Options, cmSystemTools::ParseArguments(opts)); + cm::append(P4Options, cmSystemTools::ParseArguments(opts)); } CommandOptions.clear(); diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 3091050..7d0f69b 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -34,9 +34,6 @@ cmCTestRunTest::cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler) this->TestResult.Status = cmCTestTestHandler::NOT_RUN; this->TestResult.TestCount = 0; this->TestResult.Properties = nullptr; - this->NumberOfRunsLeft = 1; // default to 1 run of the test - this->RunUntilFail = false; // default to run the test once - this->RunAgain = false; // default to not having to run again } void cmCTestRunTest::CheckOutput(std::string const& line) @@ -310,43 +307,52 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) } // If the test does not need to rerun push the current TestResult onto the // TestHandler vector - if (!this->NeedsToRerun()) { + if (!this->NeedsToRepeat()) { this->TestHandler->TestResults.push_back(this->TestResult); } this->TestProcess.reset(); return passed || skipped; } -bool cmCTestRunTest::StartAgain(size_t completed) +bool cmCTestRunTest::StartAgain(std::unique_ptr<cmCTestRunTest> runner, + size_t completed) { - if (!this->RunAgain) { + auto* testRun = runner.get(); + + if (!testRun->RunAgain) { return false; } - this->RunAgain = false; // reset + testRun->RunAgain = false; // reset + testRun->TestProcess = cm::make_unique<cmProcess>(std::move(runner)); // change to tests directory - cmWorkingDirectory workdir(this->TestProperties->Directory); + cmWorkingDirectory workdir(testRun->TestProperties->Directory); if (workdir.Failed()) { - this->StartFailure("Failed to change working directory to " + - this->TestProperties->Directory + " : " + - std::strerror(workdir.GetLastResult())); + testRun->StartFailure("Failed to change working directory to " + + testRun->TestProperties->Directory + " : " + + std::strerror(workdir.GetLastResult()), + "Failed to change working directory"); return true; } - this->StartTest(completed, this->TotalNumberOfTests); + testRun->StartTest(completed, testRun->TotalNumberOfTests); return true; } -bool cmCTestRunTest::NeedsToRerun() +bool cmCTestRunTest::NeedsToRepeat() { this->NumberOfRunsLeft--; if (this->NumberOfRunsLeft == 0) { return false; } // if number of runs left is not 0, and we are running until - // we find a failed test, then return true so the test can be + // we find a failed (or passed) test, then return true so the test can be // restarted - if (this->RunUntilFail && - this->TestResult.Status == cmCTestTestHandler::COMPLETED) { + if ((this->RepeatMode == cmCTest::Repeat::UntilFail && + this->TestResult.Status == cmCTestTestHandler::COMPLETED) || + (this->RepeatMode == cmCTest::Repeat::UntilPass && + this->TestResult.Status != cmCTestTestHandler::COMPLETED) || + (this->RepeatMode == cmCTest::Repeat::AfterTimeout && + this->TestResult.Status == cmCTestTestHandler::TIMEOUT)) { this->RunAgain = true; return true; } @@ -380,7 +386,20 @@ void cmCTestRunTest::MemCheckPostProcess() handler->PostProcessTest(this->TestResult, this->Index); } -void cmCTestRunTest::StartFailure(std::string const& output) +void cmCTestRunTest::StartFailure(std::unique_ptr<cmCTestRunTest> runner, + std::string const& output, + std::string const& detail) +{ + auto* testRun = runner.get(); + + testRun->TestProcess = cm::make_unique<cmProcess>(std::move(runner)); + testRun->StartFailure(output, detail); + + testRun->FinalizeTest(false); +} + +void cmCTestRunTest::StartFailure(std::string const& output, + std::string const& detail) { // Still need to log the Start message so the test summary records our // attempt to start this test @@ -403,14 +422,13 @@ void cmCTestRunTest::StartFailure(std::string const& output) this->TestResult.ExecutionTime = cmDuration::zero(); this->TestResult.CompressOutput = false; this->TestResult.ReturnValue = -1; - this->TestResult.CompletionStatus = "Failed to start"; + this->TestResult.CompletionStatus = detail; this->TestResult.Status = cmCTestTestHandler::NOT_RUN; this->TestResult.TestCount = this->TestProperties->Index; this->TestResult.Name = this->TestProperties->Name; this->TestResult.Path = this->TestProperties->Directory; this->TestResult.Output = output; this->TestResult.FullCommandLine.clear(); - this->TestProcess = cm::make_unique<cmProcess>(*this); } std::string cmCTestRunTest::GetTestPrefix(size_t completed, size_t total) const @@ -434,6 +452,21 @@ std::string cmCTestRunTest::GetTestPrefix(size_t completed, size_t total) const return outputStream.str(); } +bool cmCTestRunTest::StartTest(std::unique_ptr<cmCTestRunTest> runner, + size_t completed, size_t total) +{ + auto* testRun = runner.get(); + + testRun->TestProcess = cm::make_unique<cmProcess>(std::move(runner)); + + if (!testRun->StartTest(completed, total)) { + testRun->FinalizeTest(false); + return false; + } + + return true; +} + // Starts the execution of a test. Returns once it has started bool cmCTestRunTest::StartTest(size_t completed, size_t total) { @@ -465,7 +498,6 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total) if (this->TestProperties->Disabled) { this->TestResult.CompletionStatus = "Disabled"; this->TestResult.Status = cmCTestTestHandler::NOT_RUN; - this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestResult.Output = "Disabled"; this->TestResult.FullCommandLine.clear(); return false; @@ -479,7 +511,6 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total) // its arguments are irrelevant. This matters for the case where a fixture // dependency might be creating the executable we want to run. if (!this->FailedDependencies.empty()) { - this->TestProcess = cm::make_unique<cmProcess>(*this); std::string msg = "Failed test dependencies:"; for (std::string const& failedDep : this->FailedDependencies) { msg += " " + failedDep; @@ -496,7 +527,6 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total) this->ComputeArguments(); std::vector<std::string>& args = this->TestProperties->Args; if (args.size() >= 2 && args[1] == "NOT_AVAILABLE") { - this->TestProcess = cm::make_unique<cmProcess>(*this); std::string msg; if (this->CTest->GetConfigType().empty()) { msg = "Test not available without configuration. (Missing \"-C " @@ -518,7 +548,6 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total) for (std::string const& file : this->TestProperties->RequiredFiles) { if (!cmSystemTools::FileExists(file)) { // Required file was not found - this->TestProcess = cm::make_unique<cmProcess>(*this); *this->TestHandler->LogFile << "Unable to find required file: " << file << std::endl; cmCTestLog(this->CTest, ERROR_MESSAGE, @@ -534,7 +563,6 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total) if (this->ActualCommand.empty()) { // if the command was not found create a TestResult object // that has that information - this->TestProcess = cm::make_unique<cmProcess>(*this); *this->TestHandler->LogFile << "Unable to find executable: " << args[1] << std::endl; cmCTestLog(this->CTest, ERROR_MESSAGE, @@ -646,7 +674,6 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, std::vector<std::string>* environment, std::vector<size_t>* affinity) { - this->TestProcess = cm::make_unique<cmProcess>(*this); this->TestProcess->SetId(this->Index); this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory); this->TestProcess->SetCommand(this->ActualCommand); @@ -746,7 +773,12 @@ void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) // then it will never print out the completed / total, same would // got for run until pass. Trick is when this is called we don't // yet know if we are passing or failing. - if (this->NumberOfRunsLeft == 1 || this->CTest->GetTestProgressOutput()) { + bool const progressOnLast = + (this->RepeatMode != cmCTest::Repeat::UntilPass && + this->RepeatMode != cmCTest::Repeat::AfterTimeout); + if ((progressOnLast && this->NumberOfRunsLeft == 1) || + (!progressOnLast && this->NumberOfRunsLeft == this->NumberOfRunsTotal) || + this->CTest->GetTestProgressOutput()) { outputStream << std::setw(getNumWidth(total)) << completed << "/"; outputStream << std::setw(getNumWidth(total)) << total << " "; } @@ -808,7 +840,8 @@ void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total) "Testing " << this->TestProperties->Name << " ... "); } -void cmCTestRunTest::FinalizeTest() +void cmCTestRunTest::FinalizeTest(bool started) { - this->MultiTestHandler.FinishTestProcess(this, true); + this->MultiTestHandler.FinishTestProcess(this->TestProcess->GetRunner(), + started); } diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index f781c7a..b1d188a 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -13,13 +13,12 @@ #include <stddef.h> +#include "cmCTest.h" #include "cmCTestMultiProcessHandler.h" #include "cmCTestTestHandler.h" #include "cmDuration.h" #include "cmProcess.h" -class cmCTest; - /** \class cmRunTest * \brief represents a single test to be run * @@ -30,8 +29,13 @@ class cmCTestRunTest public: explicit cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler); - void SetNumberOfRuns(int n) { this->NumberOfRunsLeft = n; } - void SetRunUntilFailOn() { this->RunUntilFail = true; } + void SetNumberOfRuns(int n) + { + this->NumberOfRunsLeft = n; + this->NumberOfRunsTotal = n; + } + + void SetRepeatMode(cmCTest::Repeat r) { this->RepeatMode = r; } void SetTestProperties(cmCTestTestHandler::cmCTestTestProperties* prop) { this->TestProperties = prop; @@ -61,6 +65,15 @@ public: // Read and store output. Returns true if it must be called again. void CheckOutput(std::string const& line); + static bool StartTest(std::unique_ptr<cmCTestRunTest> runner, + size_t completed, size_t total); + static bool StartAgain(std::unique_ptr<cmCTestRunTest> runner, + size_t completed); + + static void StartFailure(std::unique_ptr<cmCTestRunTest> runner, + std::string const& output, + std::string const& detail); + // launch the test process, return whether it started correctly bool StartTest(size_t completed, size_t total); // capture and report the test results @@ -70,9 +83,7 @@ public: void ComputeWeightedCost(); - bool StartAgain(size_t completed); - - void StartFailure(std::string const& output); + void StartFailure(std::string const& output, std::string const& detail); cmCTest* GetCTest() const { return this->CTest; } @@ -80,7 +91,7 @@ public: const std::vector<std::string>& GetArguments() { return this->Arguments; } - void FinalizeTest(); + void FinalizeTest(bool started = true); bool TimedOutForStopTime() const { return this->TimeoutIsForStopTime; } @@ -98,7 +109,7 @@ public: } private: - bool NeedsToRerun(); + bool NeedsToRepeat(); void DartProcessing(); void ExeNotFound(std::string exe); bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout, @@ -132,9 +143,10 @@ private: std::vector<std::map< std::string, std::vector<cmCTestMultiProcessHandler::ResourceAllocation>>> AllocatedResources; - bool RunUntilFail; - int NumberOfRunsLeft; - bool RunAgain; + cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never; + int NumberOfRunsLeft = 1; // default to 1 run of the test + int NumberOfRunsTotal = 1; // default to 1 run of the test + bool RunAgain = false; // default to not having to run again size_t TotalNumberOfTests; }; diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index 34395c9..44dfab2 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -7,9 +7,10 @@ #include <map> #include <ostream> +#include <cmext/algorithm> + #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestVC.h" #include "cmProcessTools.h" @@ -271,7 +272,7 @@ bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters, std::vector<char const*> args; args.push_back(this->CommandLineTool.c_str()); - cmAppend(args, parameters); + cm::append(args, parameters); args.push_back("--non-interactive"); std::string userOptions = this->CTest->GetCTestConfiguration("SVNOptions"); @@ -344,7 +345,7 @@ private: void CharacterDataHandler(const char* data, int length) override { - cmAppend(this->CData, data, data + length); + cm::append(this->CData, data, data + length); } void EndElement(const std::string& name) override diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 60facbd..5be9332 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -6,7 +6,6 @@ #include <cstdlib> #include <cstring> #include <map> -#include <memory> #include <ratio> #include <sstream> #include <utility> @@ -51,22 +50,7 @@ #define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log" -cmCTestScriptHandler::cmCTestScriptHandler() -{ - this->Backup = false; - this->EmptyBinDir = false; - this->EmptyBinDirOnce = false; - this->Makefile = nullptr; - this->ParentMakefile = nullptr; - this->CMake = nullptr; - this->GlobalGenerator = nullptr; - - this->ScriptStartTime = std::chrono::steady_clock::time_point(); - - // the *60 is because the settings are in minutes but GetTime is seconds - this->MinimumInterval = 30 * 60; - this->ContinuousDuration = -1; -} +cmCTestScriptHandler::cmCTestScriptHandler() = default; void cmCTestScriptHandler::Initialize() { @@ -95,22 +79,15 @@ void cmCTestScriptHandler::Initialize() // what time in seconds did this script start running this->ScriptStartTime = std::chrono::steady_clock::time_point(); - delete this->Makefile; - this->Makefile = nullptr; + this->Makefile.reset(); this->ParentMakefile = nullptr; - delete this->GlobalGenerator; - this->GlobalGenerator = nullptr; + this->GlobalGenerator.reset(); - delete this->CMake; + this->CMake.reset(); } -cmCTestScriptHandler::~cmCTestScriptHandler() -{ - delete this->Makefile; - delete this->GlobalGenerator; - delete this->CMake; -} +cmCTestScriptHandler::~cmCTestScriptHandler() = default; // just adds an argument to the vector void cmCTestScriptHandler::AddConfigurationScript(const char* script, @@ -247,23 +224,20 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg) void cmCTestScriptHandler::CreateCMake() { // create a cmake instance to read the configuration script - if (this->CMake) { - delete this->CMake; - delete this->GlobalGenerator; - delete this->Makefile; - } - this->CMake = new cmake(cmake::RoleScript, cmState::CTest); + this->CMake = cm::make_unique<cmake>(cmake::RoleScript, cmState::CTest); this->CMake->SetHomeDirectory(""); this->CMake->SetHomeOutputDirectory(""); this->CMake->GetCurrentSnapshot().SetDefaultDefinitions(); this->CMake->AddCMakePaths(); - this->GlobalGenerator = new cmGlobalGenerator(this->CMake); + this->GlobalGenerator = + cm::make_unique<cmGlobalGenerator>(this->CMake.get()); cmStateSnapshot snapshot = this->CMake->GetCurrentSnapshot(); std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); snapshot.GetDirectory().SetCurrentSource(cwd); snapshot.GetDirectory().SetCurrentBinary(cwd); - this->Makefile = new cmMakefile(this->GlobalGenerator, snapshot); + this->Makefile = + cm::make_unique<cmMakefile>(this->GlobalGenerator.get(), snapshot); if (this->ParentMakefile) { this->Makefile->SetRecursionDepth( this->ParentMakefile->GetRecursionDepth()); @@ -340,6 +314,13 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg) this->SetRunCurrentScript(true); this->UpdateElapsedTime(); + // set the CTEST_CONFIGURATION_TYPE variable to the current value of the + // the -C argument on the command line. + if (!this->CTest->GetConfigType().empty()) { + this->Makefile->AddDefinition("CTEST_CONFIGURATION_TYPE", + this->CTest->GetConfigType()); + } + // add the script arg if defined if (!script_arg.empty()) { this->Makefile->AddDefinition("CTEST_SCRIPT_ARG", script_arg); @@ -871,7 +852,7 @@ bool cmCTestScriptHandler::RunScript(cmCTest* ctest, cmMakefile* mf, const char* sname, bool InProcess, int* returnValue) { - cmCTestScriptHandler* sh = new cmCTestScriptHandler(); + auto sh = cm::make_unique<cmCTestScriptHandler>(); sh->SetCTestInstance(ctest); sh->ParentMakefile = mf; sh->AddConfigurationScript(sname, InProcess); @@ -879,7 +860,6 @@ bool cmCTestScriptHandler::RunScript(cmCTest* ctest, cmMakefile* mf, if (returnValue) { *returnValue = res; } - delete sh; return true; } diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h index d003199..ebb7905 100644 --- a/Source/CTest/cmCTestScriptHandler.h +++ b/Source/CTest/cmCTestScriptHandler.h @@ -101,12 +101,14 @@ public: cmDuration GetRemainingTimeAllowed(); cmCTestScriptHandler(); + cmCTestScriptHandler(const cmCTestScriptHandler&) = delete; + const cmCTestScriptHandler& operator=(const cmCTestScriptHandler&) = delete; ~cmCTestScriptHandler() override; void Initialize() override; void CreateCMake(); - cmake* GetCMake() { return this->CMake; } + cmake* GetCMake() { return this->CMake.get(); } void SetRunCurrentScript(bool value); @@ -143,9 +145,9 @@ private: bool ShouldRunCurrentScript; - bool Backup; - bool EmptyBinDir; - bool EmptyBinDirOnce; + bool Backup = false; + bool EmptyBinDir = false; + bool EmptyBinDirOnce = false; std::string SourceDir; std::string BinaryDir; @@ -161,16 +163,18 @@ private: std::string CMOutFile; std::vector<std::string> ExtraUpdates; - double MinimumInterval; - double ContinuousDuration; + // the *60 is because the settings are in minutes but GetTime is seconds + double MinimumInterval = 30 * 60; + double ContinuousDuration = -1; // what time in seconds did this script start running - std::chrono::steady_clock::time_point ScriptStartTime; + std::chrono::steady_clock::time_point ScriptStartTime = + std::chrono::steady_clock::time_point(); - cmMakefile* Makefile; - cmMakefile* ParentMakefile; - cmGlobalGenerator* GlobalGenerator; - cmake* CMake; + std::unique_ptr<cmMakefile> Makefile; + cmMakefile* ParentMakefile = nullptr; + std::unique_ptr<cmGlobalGenerator> GlobalGenerator; + std::unique_ptr<cmake> CMake; }; #endif diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index 46b00b1..acb75b2 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -7,6 +7,7 @@ #include <utility> #include <cm/memory> +#include <cm/vector> #include "cm_static_string_view.hxx" @@ -174,7 +175,7 @@ void cmCTestSubmitCommand::CheckArguments( this->PartsMentioned = !this->Parts.empty() || cmContains(keywords, "PARTS"); this->FilesMentioned = !this->Files.empty() || cmContains(keywords, "FILES"); - cmEraseIf(this->Parts, [this](std::string const& arg) -> bool { + cm::erase_if(this->Parts, [this](std::string const& arg) -> bool { cmCTest::Part p = this->CTest->GetPartFromName(arg.c_str()); if (p == cmCTest::PartCount) { std::ostringstream e; @@ -185,7 +186,7 @@ void cmCTestSubmitCommand::CheckArguments( return false; }); - cmEraseIf(this->Files, [this](std::string const& arg) -> bool { + cm::erase_if(this->Files, [this](std::string const& arg) -> bool { if (!cmSystemTools::FileExists(arg)) { std::ostringstream e; e << "File \"" << arg << "\" does not exist. Cannot submit " diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 2ac5af6..22ab48f 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -7,6 +7,8 @@ #include <cstdlib> #include <sstream> +#include <cmext/algorithm> + #include "cm_curl.h" #include "cm_jsoncpp_reader.h" #include "cm_jsoncpp_value.h" @@ -65,7 +67,7 @@ private: void CharacterDataHandler(const char* data, int length) override { - cmAppend(this->CurrentValue, data, data + length); + cm::append(this->CurrentValue, data, data + length); } void EndElement(const std::string& name) override @@ -96,8 +98,8 @@ static size_t cmCTestSubmitHandlerWriteMemoryCallback(void* ptr, size_t size, { int realsize = static_cast<int>(size * nmemb); const char* chPtr = static_cast<char*>(ptr); - cmAppend(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr, - chPtr + realsize); + cm::append(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr, + chPtr + realsize); return realsize; } @@ -106,9 +108,9 @@ static size_t cmCTestSubmitHandlerCurlDebugCallback(CURL* /*unused*/, char* chPtr, size_t size, void* data) { - cmAppend(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr, - chPtr + size); - return size; + cm::append(*static_cast<cmCTestSubmitHandlerVectorOfChar*>(data), chPtr, + chPtr + size); + return 0; } cmCTestSubmitHandler::cmCTestSubmitHandler() @@ -768,7 +770,7 @@ int cmCTestSubmitHandler::ProcessHandler() if (!this->Files.empty()) { // Submit the explicitly selected files: - cmAppend(files, this->Files); + cm::append(files, this->Files); } // Add to the list of files to submit from any selected, existing parts: @@ -814,7 +816,7 @@ int cmCTestSubmitHandler::ProcessHandler() } // Submit files from this part. - cmAppend(files, this->CTest->GetSubmitFiles(p)); + cm::append(files, this->CTest->GetSubmitFiles(p)); } // Make sure files are unique, but preserve order. diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx index 9784214..0f9b695 100644 --- a/Source/CTest/cmCTestTestCommand.cxx +++ b/Source/CTest/cmCTestTestCommand.cxx @@ -29,6 +29,7 @@ void cmCTestTestCommand::BindArguments() this->Bind("EXCLUDE_FIXTURE_SETUP"_s, this->ExcludeFixtureSetup); this->Bind("EXCLUDE_FIXTURE_CLEANUP"_s, this->ExcludeFixtureCleanup); this->Bind("PARALLEL_LEVEL"_s, this->ParallelLevel); + this->Bind("REPEAT"_s, this->Repeat); this->Bind("SCHEDULE_RANDOM"_s, this->ScheduleRandom); this->Bind("STOP_TIME"_s, this->StopTime); this->Bind("TEST_LOAD"_s, this->TestLoad); @@ -85,6 +86,9 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() if (!this->ParallelLevel.empty()) { handler->SetOption("ParallelLevel", this->ParallelLevel.c_str()); } + if (!this->Repeat.empty()) { + handler->SetOption("Repeat", this->Repeat.c_str()); + } if (!this->ScheduleRandom.empty()) { handler->SetOption("ScheduleRandom", this->ScheduleRandom.c_str()); } diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h index 4019694..2345afb 100644 --- a/Source/CTest/cmCTestTestCommand.h +++ b/Source/CTest/cmCTestTestCommand.h @@ -55,6 +55,7 @@ protected: std::string ExcludeFixtureSetup; std::string ExcludeFixtureCleanup; std::string ParallelLevel; + std::string Repeat; std::string ScheduleRandom; std::string StopTime; std::string TestLoad; diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index c8bbb0b..8513f4b 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -410,10 +410,15 @@ int cmCTestTestHandler::ProcessHandler() auto clock_finish = std::chrono::steady_clock::now(); + bool noTestsFoundError = false; if (passed.size() + failed.size() == 0) { - if (!this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels()) { + if (!this->CTest->GetShowOnly() && !this->CTest->ShouldPrintLabels() && + this->CTest->GetNoTestsMode() != cmCTest::NoTests::Ignore) { cmCTestLog(this->CTest, ERROR_MESSAGE, "No tests were found!!!" << std::endl); + if (this->CTest->GetNoTestsMode() == cmCTest::NoTests::Error) { + noTestsFoundError = true; + } } } else { if (this->HandlerVerbose && !passed.empty() && @@ -459,6 +464,12 @@ int cmCTestTestHandler::ProcessHandler() this->LogFile = nullptr; return -1; } + + if (noTestsFoundError) { + this->LogFile = nullptr; + return -1; + } + this->LogFile = nullptr; return 0; } @@ -471,6 +482,30 @@ bool cmCTestTestHandler::ProcessOptions() if (cmIsOn(this->GetOption("ScheduleRandom"))) { this->CTest->SetScheduleType("Random"); } + if (const char* repeat = this->GetOption("Repeat")) { + cmsys::RegularExpression repeatRegex( + "^(UNTIL_FAIL|UNTIL_PASS|AFTER_TIMEOUT):([0-9]+)$"); + if (repeatRegex.find(repeat)) { + std::string const& count = repeatRegex.match(2); + unsigned long n = 1; + cmStrToULong(count, &n); // regex guarantees success + this->RepeatCount = static_cast<int>(n); + if (this->RepeatCount > 1) { + std::string const& mode = repeatRegex.match(1); + if (mode == "UNTIL_FAIL") { + this->RepeatMode = cmCTest::Repeat::UntilFail; + } else if (mode == "UNTIL_PASS") { + this->RepeatMode = cmCTest::Repeat::UntilPass; + } else if (mode == "AFTER_TIMEOUT") { + this->RepeatMode = cmCTest::Repeat::AfterTimeout; + } + } + } else { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Repeat option invalid value: " << repeat << std::endl); + return false; + } + } if (this->GetOption("ParallelLevel")) { this->CTest->SetParallelLevel(atoi(this->GetOption("ParallelLevel"))); } @@ -513,6 +548,7 @@ bool cmCTestTestHandler::ProcessOptions() val = this->GetOption("ResourceSpecFile"); if (val) { this->UseResourceSpec = true; + this->ResourceSpecFile = val; auto result = this->ResourceSpec.ReadFromJSONFile(val); if (result != cmCTestResourceSpec::ReadFileResult::READ_OK) { cmCTestLog(this->CTest, ERROR_MESSAGE, @@ -1231,10 +1267,16 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed, this->StartTestTime = std::chrono::system_clock::now(); auto elapsed_time_start = std::chrono::steady_clock::now(); - cmCTestMultiProcessHandler* parallel = new cmCTestMultiProcessHandler; + auto parallel = cm::make_unique<cmCTestMultiProcessHandler>(); parallel->SetCTest(this->CTest); parallel->SetParallelLevel(this->CTest->GetParallelLevel()); parallel->SetTestHandler(this); + if (this->RepeatMode != cmCTest::Repeat::Never) { + parallel->SetRepeatMode(this->RepeatMode, this->RepeatCount); + } else { + parallel->SetRepeatMode(this->CTest->GetRepeatMode(), + this->CTest->GetRepeatCount()); + } parallel->SetQuiet(this->Quiet); if (this->TestLoad > 0) { parallel->SetTestLoad(this->TestLoad); @@ -1296,7 +1338,6 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed, } else { parallel->RunTests(); } - delete parallel; this->EndTest = this->CTest->CurrentTime(); this->EndTestTime = std::chrono::system_clock::now(); this->ElapsedTestingTime = @@ -1974,13 +2015,13 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, | std::ios::binary #endif ); - unsigned char* file_buffer = new unsigned char[len + 1]; - ifs.read(reinterpret_cast<char*>(file_buffer), len); - unsigned char* encoded_buffer = new unsigned char[static_cast<int>( - static_cast<double>(len) * 1.5 + 5.0)]; + auto file_buffer = cm::make_unique<unsigned char[]>(len + 1); + ifs.read(reinterpret_cast<char*>(file_buffer.get()), len); + auto encoded_buffer = cm::make_unique<unsigned char[]>( + static_cast<int>(static_cast<double>(len) * 1.5 + 5.0)); - size_t rlen = - cmsysBase64_Encode(file_buffer, len, encoded_buffer, 1); + size_t rlen = cmsysBase64_Encode(file_buffer.get(), len, + encoded_buffer.get(), 1); xml.StartElement("NamedMeasurement"); xml.Attribute(measurementfile.match(1).c_str(), @@ -1997,8 +2038,6 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, } xml.Element("Value", ostr.str()); xml.EndElement(); // NamedMeasurement - delete[] file_buffer; - delete[] encoded_buffer; } } else { int idx = 4; @@ -2043,11 +2082,10 @@ void cmCTestTestHandler::SetTestsToRunInformation(const char* in) if (cmSystemTools::FileExists(in)) { cmsys::ifstream fin(in); unsigned long filelen = cmSystemTools::FileLength(in); - char* buff = new char[filelen + 1]; - fin.getline(buff, filelen); + auto buff = cm::make_unique<char[]>(filelen + 1); + fin.getline(buff.get(), filelen); buff[fin.gcount()] = 0; - this->TestsToRunString = buff; - delete[] buff; + this->TestsToRunString = buff.get(); } } diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index eab75d0..b1c8755 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -18,12 +18,12 @@ #include "cmsys/RegularExpression.hxx" +#include "cmCTest.h" #include "cmCTestGenericHandler.h" #include "cmCTestResourceSpec.h" #include "cmDuration.h" #include "cmListFileCache.h" -class cmCTest; class cmMakefile; class cmXMLWriter; @@ -338,6 +338,7 @@ private: bool UseResourceSpec; cmCTestResourceSpec ResourceSpec; + std::string ResourceSpecFile; void GenerateRegressionImages(cmXMLWriter& xml, const std::string& dart); cmsys::RegularExpression DartStuff1; @@ -353,6 +354,8 @@ private: std::ostream* LogFile; + cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never; + int RepeatCount = 1; bool RerunFailed; }; diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx index d0e3848..eaef1ca 100644 --- a/Source/CTest/cmCTestUploadCommand.cxx +++ b/Source/CTest/cmCTestUploadCommand.cxx @@ -4,11 +4,11 @@ #include <set> #include <sstream> -#include <vector> + +#include <cm/vector> #include "cm_static_string_view.hxx" -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestUploadHandler.h" #include "cmMakefile.h" @@ -24,7 +24,7 @@ void cmCTestUploadCommand::BindArguments() void cmCTestUploadCommand::CheckArguments(std::vector<std::string> const&) { - cmEraseIf(this->Files, [this](std::string const& arg) -> bool { + cm::erase_if(this->Files, [this](std::string const& arg) -> bool { if (!cmSystemTools::FileExists(arg)) { std::ostringstream e; e << "File \"" << arg << "\" does not exist. Cannot submit " diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx index 6026c69..452d714 100644 --- a/Source/CTest/cmCTestVC.cxx +++ b/Source/CTest/cmCTestVC.cxx @@ -38,7 +38,7 @@ void cmCTestVC::SetSourceDirectory(std::string const& dir) this->SourceDirectory = dir; } -bool cmCTestVC::InitialCheckout(const char* command) +bool cmCTestVC::InitialCheckout(const std::string& command) { cmCTestLog(this->CTest, HANDLER_OUTPUT, " First perform the initial checkout: " << command << "\n"); diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h index 2a4765d..3037e01 100644 --- a/Source/CTest/cmCTestVC.h +++ b/Source/CTest/cmCTestVC.h @@ -36,7 +36,7 @@ public: std::string GetNightlyTime(); /** Prepare the work tree. */ - bool InitialCheckout(const char* command); + bool InitialCheckout(const std::string& command); /** Perform cleanup operations on the work tree. */ void Cleanup(); diff --git a/Source/CTest/cmParsePHPCoverage.cxx b/Source/CTest/cmParsePHPCoverage.cxx index a494b92..044f518 100644 --- a/Source/CTest/cmParsePHPCoverage.cxx +++ b/Source/CTest/cmParsePHPCoverage.cxx @@ -3,6 +3,8 @@ #include <cstdlib> #include <cstring> +#include <cm/memory> + #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" @@ -142,17 +144,15 @@ bool cmParsePHPCoverage::ReadFileInformation(std::istream& in) int size = 0; if (this->ReadInt(in, size)) { size++; // add one for null termination - char* s = new char[size + 1]; + auto s = cm::make_unique<char[]>(size + 1); // read open quote if (in.get(c) && c != '"') { - delete[] s; return false; } // read the string data - in.read(s, size - 1); + in.read(s.get(), size - 1); s[size - 1] = 0; - std::string fileName = s; - delete[] s; + std::string fileName = s.get(); // read close quote if (in.get(c) && c != '"') { cmCTestLog(this->CTest, ERROR_MESSAGE, diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 87f7147..76ffb20 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -5,10 +5,12 @@ #include <csignal> #include <iostream> #include <string> +#include <utility> + +#include <cmext/algorithm> #include "cmsys/Process.h" -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestRunTest.h" #include "cmCTestTestHandler.h" @@ -17,12 +19,11 @@ #if defined(_WIN32) # include "cm_kwiml.h" #endif -#include <utility> #define CM_PROCESS_BUF_SIZE 65536 -cmProcess::cmProcess(cmCTestRunTest& runner) - : Runner(runner) +cmProcess::cmProcess(std::unique_ptr<cmCTestRunTest> runner) + : Runner(std::move(runner)) , Conv(cmProcessOutput::UTF8, CM_PROCESS_BUF_SIZE) { this->Timeout = cmDuration::zero(); @@ -68,7 +69,7 @@ bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity) cm::uv_timer_ptr timer; int status = timer.init(loop, this); if (status != 0) { - cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + cmCTestLog(this->Runner->GetCTest(), ERROR_MESSAGE, "Error initializing timer: " << uv_strerror(status) << std::endl); return false; @@ -83,7 +84,7 @@ bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity) int fds[2] = { -1, -1 }; status = cmGetPipes(fds); if (status != 0) { - cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + cmCTestLog(this->Runner->GetCTest(), ERROR_MESSAGE, "Error initializing pipe: " << uv_strerror(status) << std::endl); return false; @@ -126,7 +127,7 @@ bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity) uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB); if (status != 0) { - cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + cmCTestLog(this->Runner->GetCTest(), ERROR_MESSAGE, "Error starting read events: " << uv_strerror(status) << std::endl); return false; @@ -134,7 +135,7 @@ bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity) status = this->Process.spawn(loop, options, this); if (status != 0) { - cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + cmCTestLog(this->Runner->GetCTest(), ERROR_MESSAGE, "Process not started\n " << this->Command << "\n[" << uv_strerror(status) << "]\n"); return false; @@ -151,7 +152,7 @@ bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity) void cmProcess::StartTimer() { - auto properties = this->Runner.GetTestProperties(); + auto properties = this->Runner->GetTestProperties(); auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(this->Timeout); @@ -218,10 +219,10 @@ void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf) if (nread > 0) { std::string strdata; this->Conv.DecodeText(buf->base, static_cast<size_t>(nread), strdata); - cmAppend(this->Output, strdata); + cm::append(this->Output, strdata); while (this->Output.GetLine(line)) { - this->Runner.CheckOutput(line); + this->Runner->CheckOutput(line); line.clear(); } @@ -235,20 +236,20 @@ void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf) // The process will provide no more data. if (nread != UV_EOF) { auto error = static_cast<int>(nread); - cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, + cmCTestLog(this->Runner->GetCTest(), ERROR_MESSAGE, "Error reading stream: " << uv_strerror(error) << std::endl); } // Look for partial last lines. if (this->Output.GetLast(line)) { - this->Runner.CheckOutput(line); + this->Runner->CheckOutput(line); } this->ReadHandleClosed = true; this->PipeReader.reset(); if (this->ProcessHandleClosed) { uv_timer_stop(this->Timer); - this->Runner.FinalizeTest(); + this->Runner->FinalizeTest(); } } @@ -277,9 +278,6 @@ void cmProcess::OnTimeoutCB(uv_timer_t* timer) void cmProcess::OnTimeout() { - if (this->ProcessState != cmProcess::State::Executing) { - return; - } this->ProcessState = cmProcess::State::Expired; bool const was_still_reading = !this->ReadHandleClosed; if (!this->ReadHandleClosed) { @@ -293,7 +291,7 @@ void cmProcess::OnTimeout() // Our on-exit handler already ran but did not finish the test // because we were still reading output. We've just dropped // our read handler, so we need to finish the test now. - this->Runner.FinalizeTest(); + this->Runner->FinalizeTest(); } } @@ -335,7 +333,7 @@ void cmProcess::OnExit(int64_t exit_status, int term_signal) this->ProcessHandleClosed = true; if (this->ReadHandleClosed) { uv_timer_stop(this->Timer); - this->Runner.FinalizeTest(); + this->Runner->FinalizeTest(); } } diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index 2c24f2d..0f69f68 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -6,7 +6,9 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <chrono> +#include <memory> #include <string> +#include <utility> #include <vector> #include <stddef.h> @@ -28,7 +30,7 @@ class cmCTestRunTest; class cmProcess { public: - explicit cmProcess(cmCTestRunTest& runner); + explicit cmProcess(std::unique_ptr<cmCTestRunTest> runner); ~cmProcess(); void SetCommand(std::string const& command); void SetCommandArguments(std::vector<std::string> const& arg); @@ -70,6 +72,11 @@ public: Exception GetExitException(); std::string GetExitExceptionString(); + std::unique_ptr<cmCTestRunTest> GetRunner() + { + return std::move(this->Runner); + } + private: cmDuration Timeout; std::chrono::steady_clock::time_point StartTime; @@ -82,7 +89,7 @@ private: cm::uv_timer_ptr Timer; std::vector<char> Buf; - cmCTestRunTest& Runner; + std::unique_ptr<cmCTestRunTest> Runner; cmProcessOutput Conv; int Signal = 0; cmProcess::State ProcessState = cmProcess::State::Starting; diff --git a/Source/Checks/Curses.cmake b/Source/Checks/Curses.cmake index 2942b66..d35dd2a 100644 --- a/Source/Checks/Curses.cmake +++ b/Source/Checks/Curses.cmake @@ -1,4 +1,7 @@ -message(STATUS "Checking for curses support") +include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake) +cm_message_checks_compat( + "Checking for curses support" __checkStart __checkPass __checkFail) +message(${__checkStart}) # Try compiling a simple project using curses. # Pass in any cache entries that the user may have set. @@ -31,11 +34,11 @@ set(CMakeCheckCurses_COMPILED "${CMakeCheckCurses_COMPILED}") unset(CMakeCheckCurses_COMPILED CACHE) if(CMakeCheckCurses_COMPILED) - message(STATUS "Checking for curses support - Success") + message(${__checkPass} "Success") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "Checking for curses support passed with the following output:\n${CMakeCheckCurses_OUTPUT}\n\n") else() - message(STATUS "Checking for curses support - Failed") + message(${__checkFail} "Failed") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "Checking for curses support failed with the following output:\n${CMakeCheckCurses_OUTPUT}\n\n") endif() diff --git a/Source/Checks/cm_c11_thread_local.cmake b/Source/Checks/cm_c11_thread_local.cmake index 6b8d10b..2263be3 100644 --- a/Source/Checks/cm_c11_thread_local.cmake +++ b/Source/Checks/cm_c11_thread_local.cmake @@ -1,7 +1,11 @@ set(CMake_C11_THREAD_LOCAL_BROKEN 0) if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_C11_STANDARD_COMPILE_OPTION) if(NOT DEFINED CMake_C11_THREAD_LOCAL_WORKS) - message(STATUS "Checking if compiler supports C11 _Thread_local") + include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake) + cm_message_checks_compat( + "Checking if compiler supports C11 _Thread_local" + __checkStart __checkPass __checkFail) + message(${__checkStart}) try_compile(CMake_C11_THREAD_LOCAL_WORKS ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/cm_c11_thread_local.c @@ -12,14 +16,14 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_C11_STANDARD_COMPILE_OPTION) set_property(CACHE CMake_C11_THREAD_LOCAL_WORKS PROPERTY VALUE 0) endif() if(CMake_C11_THREAD_LOCAL_WORKS) - message(STATUS "Checking if compiler supports C11 _Thread_local - yes") + message(${__checkPass} "yes") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "Determining if compiler supports C11 _Thread_local passed with the following output:\n" "${OUTPUT}\n" "\n" ) else() - message(STATUS "Checking if compiler supports C11 _Thread_local - no") + message(${__checkFail} "no") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "Determining if compiler supports C11 _Thread_local failed with the following output:\n" "${OUTPUT}\n" diff --git a/Source/Checks/cm_cxx14_check.cmake b/Source/Checks/cm_cxx14_check.cmake index 38606b9..e5656bf 100644 --- a/Source/Checks/cm_cxx14_check.cmake +++ b/Source/Checks/cm_cxx14_check.cmake @@ -1,10 +1,14 @@ set(CMake_CXX14_BROKEN 0) -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI") +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI|Intel") if(NOT CMAKE_CXX14_STANDARD_COMPILE_OPTION) set(CMake_CXX14_WORKS 0) endif() if(NOT DEFINED CMake_CXX14_WORKS) - message(STATUS "Checking if compiler supports needed C++14 constructs") + include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake) + cm_message_checks_compat( + "Checking if compiler supports needed C++14 constructs" + __checkStart __checkPass __checkFail) + message(${__checkStart}) try_compile(CMake_CXX14_WORKS ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/cm_cxx14_check.cpp @@ -15,14 +19,14 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI") set_property(CACHE CMake_CXX14_WORKS PROPERTY VALUE 0) endif() if(CMake_CXX14_WORKS) - message(STATUS "Checking if compiler supports needed C++14 constructs - yes") + message(${__checkPass} "yes") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "Determining if compiler supports needed C++14 constructs passed with the following output:\n" "${OUTPUT}\n" "\n" ) else() - message(STATUS "Checking if compiler supports needed C++14 constructs - no") + message(${__checkFail} "no") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "Determining if compiler supports needed C++14 constructs failed with the following output:\n" "${OUTPUT}\n" diff --git a/Source/Checks/cm_cxx17_check.cmake b/Source/Checks/cm_cxx17_check.cmake index 4da2fd7..dba3eaf 100644 --- a/Source/Checks/cm_cxx17_check.cmake +++ b/Source/Checks/cm_cxx17_check.cmake @@ -1,10 +1,14 @@ set(CMake_CXX17_BROKEN 0) -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI") +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI|Intel") if(NOT CMAKE_CXX17_STANDARD_COMPILE_OPTION) set(CMake_CXX17_WORKS 0) endif() if(NOT DEFINED CMake_CXX17_WORKS) - message(STATUS "Checking if compiler supports needed C++17 constructs") + include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake) + cm_message_checks_compat( + "Checking if compiler supports needed C++17 constructs" + __checkStart __checkPass __checkFail) + message(${__checkStart}) try_compile(CMake_CXX17_WORKS ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/cm_cxx17_check.cpp @@ -15,14 +19,14 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI") set_property(CACHE CMake_CXX17_WORKS PROPERTY VALUE 0) endif() if(CMake_CXX17_WORKS) - message(STATUS "Checking if compiler supports needed C++17 constructs - yes") + message(${__checkPass} "yes") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "Determining if compiler supports needed C++17 constructs passed with the following output:\n" "${OUTPUT}\n" "\n" ) else() - message(STATUS "Checking if compiler supports needed C++17 constructs - no") + message(${__checkFail} "no") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "Determining if compiler supports needed C++17 constructs failed with the following output:\n" "${OUTPUT}\n" diff --git a/Source/Checks/cm_cxx17_check.cpp b/Source/Checks/cm_cxx17_check.cpp index 29863b1..abbe22c 100644 --- a/Source/Checks/cm_cxx17_check.cpp +++ b/Source/Checks/cm_cxx17_check.cpp @@ -8,6 +8,13 @@ # include <comdef.h> #endif +template <typename T, + typename std::invoke_result<decltype(&T::get), T>::type = nullptr> +typename T::pointer get_ptr(T& item) +{ + return item.get(); +} + int main() { int a[] = { 0, 1, 2 }; @@ -20,6 +27,9 @@ int main() std::unique_ptr<int> u(new int(0)); + // Intel compiler do not handle correctly 'decltype' inside 'invoke_result' + get_ptr(u); + #ifdef _MSC_VER // clang-cl has problems instantiating this constructor in C++17 mode // error: indirection requires pointer operand ('const _GUID' invalid) diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake index fb68ed7..c16286c 100644 --- a/Source/Checks/cm_cxx_features.cmake +++ b/Source/Checks/cm_cxx_features.cmake @@ -1,8 +1,12 @@ +include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake) function(cm_check_cxx_feature name) string(TOUPPER ${name} FEATURE) if(NOT DEFINED CMake_HAVE_CXX_${FEATURE}) - message(STATUS "Checking if compiler supports C++ ${name}") + cm_message_checks_compat( + "Checking if compiler supports C++ ${name}" + __checkStart __checkPass __checkFail) + message(${__checkStart}) if(CMAKE_CXX_STANDARD) set(maybe_cxx_standard -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}) else() @@ -26,19 +30,23 @@ function(cm_check_cxx_feature name) string(REGEX REPLACE "[^\n]*warning:[^\n]*sprintf\\(\\) is often misused, please use snprintf[^\n]*" "" check_output "${check_output}") # Filter out xcodebuild warnings. string(REGEX REPLACE "[^\n]* xcodebuild\\[[0-9]*:[0-9]*\\] warning: [^\n]*" "" check_output "${check_output}") + # Filter out ld warnings. + string(REGEX REPLACE "[^\n]*ld: warning: [^\n]*" "" check_output "${check_output}") + # Filter out CUDA installation warnings. + string(REGEX REPLACE "[^\n]*clang: warning: Unknown CUDA version[^\n]*" "" check_output "${check_output}") # If using the feature causes warnings, treat it as broken/unavailable. if(check_output MATCHES "(^|[ :])[Ww][Aa][Rr][Nn][Ii][Nn][Gg]") set(CMake_HAVE_CXX_${FEATURE} OFF CACHE INTERNAL "TRY_COMPILE" FORCE) endif() if(CMake_HAVE_CXX_${FEATURE}) - message(STATUS "Checking if compiler supports C++ ${name} - yes") + message(${__checkPass} "yes") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "Determining if compiler supports C++ ${name} passed with the following output:\n" "${OUTPUT}\n" "\n" ) else() - message(STATUS "Checking if compiler supports C++ ${name} - no") + message(${__checkFail} "no") file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "Determining if compiler supports C++ ${name} failed with the following output:\n" "${OUTPUT}\n" diff --git a/Source/Checks/cm_message_checks_compat.cmake b/Source/Checks/cm_message_checks_compat.cmake new file mode 100644 index 0000000..024c397 --- /dev/null +++ b/Source/Checks/cm_message_checks_compat.cmake @@ -0,0 +1,13 @@ +# Supporting using the CHECK_... message modes if available +# and fall back to the older behavior if not +macro(cm_message_checks_compat description startVar passVar failVar) + if(CMAKE_VERSION VERSION_GREATER 3.16.2019) + set(${startVar} CHECK_START "${description}") + set(${passVar} CHECK_PASS) + set(${failVar} CHECK_FAIL) + else() + set(${startVar} STATUS "${description}") + set(${passVar} STATUS "${description} - ") + set(${failVar} STATUS "${description} - ") + endif() +endmacro() diff --git a/Source/CursesDialog/CMakeLists.txt b/Source/CursesDialog/CMakeLists.txt index 7009717..c24ee76 100644 --- a/Source/CursesDialog/CMakeLists.txt +++ b/Source/CursesDialog/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(ccmake ccmake.cxx cmCursesBoolWidget.cxx cmCursesCacheEntryComposite.cxx + cmCursesColor.cxx cmCursesDummyWidget.cxx cmCursesFilePathWidget.cxx cmCursesForm.cxx @@ -17,21 +18,45 @@ add_executable(ccmake cmCursesWidget.cxx ) target_include_directories(ccmake PRIVATE ${CURSES_INCLUDE_PATH}) +set(CMAKE_REQUIRED_INCLUDES ${CURSES_INCLUDE_PATH}) target_link_libraries(ccmake CMakeLib) if(CMAKE_USE_SYSTEM_FORM) find_path(CURSES_FORM_INCLUDE_DIR NAMES form.h HINTS ${CURSES_INCLUDE_PATH} ${CURSES_INCLUDE_PATH}/ncurses) if(CURSES_FORM_INCLUDE_DIR) target_include_directories(ccmake PRIVATE ${CURSES_FORM_INCLUDE_DIR}) + list(APPEND CMAKE_REQUIRED_INCLUDES ${CURSES_FORM_INCLUDE_DIR}) endif() target_link_libraries(ccmake ${CURSES_FORM_LIBRARY} ${CURSES_LIBRARY} ) + set(CMAKE_REQUIRED_LIBRARIES + ${CURSES_FORM_LIBRARY} + ${CURSES_LIBRARY} + ) if(CURSES_EXTRA_LIBRARY) target_link_libraries(ccmake ${CURSES_EXTRA_LIBRARY}) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${CURSES_EXTRA_LIBRARY}) endif() else() target_link_libraries(ccmake cmForm) + get_target_property(cmFormIncludeDirs cmForm INTERFACE_INCLUDE_DIRECTORIES) + list(APPEND CMAKE_REQUIRED_INCLUDES ${cmFormIncludeDirs}) + get_target_property(cmFormLibraries cmForm INTERFACE_LINK_LIBRARIES) + set(CMAKE_REQUIRED_LIBRARIES ${cmFormLibraries}) +endif() + +include(CheckSymbolExists) +check_symbol_exists(use_default_colors + "form.h" + HAVE_CURSES_USE_DEFAULT_COLORS) +if(HAVE_CURSES_USE_DEFAULT_COLORS) + set_source_files_properties(cmCursesColor.cxx + PROPERTIES COMPILE_DEFINITIONS HAVE_CURSES_USE_DEFAULT_COLORS) +endif() + +if(CMake_JOB_POOL_LINK_BIN) + set_property(TARGET ccmake PROPERTY JOB_POOL_LINK "link-bin") endif() CMake_OPTIONAL_COMPONENT(ccmake) diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx index 9e9dfbd..01fce85 100644 --- a/Source/CursesDialog/ccmake.cxx +++ b/Source/CursesDialog/ccmake.cxx @@ -9,6 +9,7 @@ #include "cmsys/Encoding.hxx" +#include "cmCursesColor.h" #include "cmCursesForm.h" #include "cmCursesMainForm.h" #include "cmCursesStandardIncludes.h" @@ -126,6 +127,7 @@ int main(int argc, char const* const* argv) noecho(); /* Echo off */ cbreak(); /* nl- or cr not needed */ keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ + cmCursesColor::InitColors(); signal(SIGWINCH, onsig); @@ -153,10 +155,28 @@ int main(int argc, char const* const* argv) return 1; } + /* + * The message is stored in a list by the form which will be + * joined by '\n' before display. + * Removing any trailing '\n' avoid extra empty lines in the final results + */ + auto cleanMessage = [](const std::string& message) -> std::string { + auto msg = message; + if (!msg.empty() && msg.back() == '\n') { + msg.pop_back(); + } + return msg; + }; cmSystemTools::SetMessageCallback( - [myform](const std::string& message, const char* title) { - myform->AddError(message, title); + [&](const std::string& message, const char* title) { + myform->AddError(cleanMessage(message), title); }); + cmSystemTools::SetStderrCallback([&](const std::string& message) { + myform->AddError(cleanMessage(message), ""); + }); + cmSystemTools::SetStdoutCallback([&](const std::string& message) { + myform->UpdateProgress(cleanMessage(message), -1); + }); cmCursesForm::CurrentForm = myform; diff --git a/Source/CursesDialog/cmCursesBoolWidget.cxx b/Source/CursesDialog/cmCursesBoolWidget.cxx index 97b0811..c4dbed8 100644 --- a/Source/CursesDialog/cmCursesBoolWidget.cxx +++ b/Source/CursesDialog/cmCursesBoolWidget.cxx @@ -4,6 +4,7 @@ #include <string> +#include "cmCursesColor.h" #include "cmCursesWidget.h" #include "cmStateTypes.h" @@ -12,8 +13,10 @@ cmCursesBoolWidget::cmCursesBoolWidget(int width, int height, int left, : cmCursesWidget(width, height, left, top) { this->Type = cmStateEnums::BOOL; - set_field_fore(this->Field, A_NORMAL); - set_field_back(this->Field, A_STANDOUT); + if (!cmCursesColor::HasColors()) { + set_field_fore(this->Field, A_NORMAL); + set_field_back(this->Field, A_STANDOUT); + } field_opts_off(this->Field, O_STATIC); this->SetValueAsBool(false); } @@ -42,8 +45,16 @@ void cmCursesBoolWidget::SetValueAsBool(bool value) { if (value) { this->SetValue("ON"); + if (cmCursesColor::HasColors()) { + set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::BoolOn)); + set_field_back(this->Field, COLOR_PAIR(cmCursesColor::BoolOn)); + } } else { this->SetValue("OFF"); + if (cmCursesColor::HasColors()) { + set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::BoolOff)); + set_field_back(this->Field, COLOR_PAIR(cmCursesColor::BoolOff)); + } } } diff --git a/Source/CursesDialog/cmCursesColor.cxx b/Source/CursesDialog/cmCursesColor.cxx new file mode 100644 index 0000000..641d48c --- /dev/null +++ b/Source/CursesDialog/cmCursesColor.cxx @@ -0,0 +1,29 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCursesColor.h" + +#include "cmCursesStandardIncludes.h" + +bool cmCursesColor::HasColors() +{ +#ifdef HAVE_CURSES_USE_DEFAULT_COLORS + return has_colors(); +#else + return false; +#endif +} + +void cmCursesColor::InitColors() +{ +#ifdef HAVE_CURSES_USE_DEFAULT_COLORS + if (HasColors()) { + start_color(); + use_default_colors(); + init_pair(cmCursesColor::BoolOff, COLOR_RED, -1); + init_pair(cmCursesColor::BoolOn, COLOR_GREEN, -1); + init_pair(cmCursesColor::String, COLOR_BLUE, -1); + init_pair(cmCursesColor::Path, COLOR_YELLOW, -1); + init_pair(cmCursesColor::Options, COLOR_MAGENTA, -1); + } +#endif +} diff --git a/Source/CursesDialog/cmCursesColor.h b/Source/CursesDialog/cmCursesColor.h new file mode 100644 index 0000000..78ca52c --- /dev/null +++ b/Source/CursesDialog/cmCursesColor.h @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCursesColor_h +#define cmCursesColor_h + +class cmCursesColor +{ +public: + enum Color + { + // Default color is pair 0 + BoolOff = 1, + BoolOn, + String, + Path, + Options + }; + + static bool HasColors(); + + static void InitColors(); +}; + +#endif // cmCursesColor_h diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx index e2d8d06..806e663 100644 --- a/Source/CursesDialog/cmCursesLongMessageForm.cxx +++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx @@ -8,6 +8,7 @@ #include "cmCursesForm.h" #include "cmCursesMainForm.h" #include "cmCursesStandardIncludes.h" +#include "cmStringAlgorithms.h" #include "cmVersion.h" inline int ctrl(int z) @@ -16,14 +17,12 @@ inline int ctrl(int z) } cmCursesLongMessageForm::cmCursesLongMessageForm( - std::vector<std::string> const& messages, const char* title) + std::vector<std::string> const& messages, const char* title, + ScrollBehavior scrollBehavior) + : Scrolling(scrollBehavior) { // Append all messages into on big string - for (std::string const& message : messages) { - this->Messages += message; - // Add one blank line after each message - this->Messages += "\n\n"; - } + this->Messages = cmJoin(messages, "\n"); this->Title = title; this->Fields[0] = nullptr; this->Fields[1] = nullptr; @@ -48,7 +47,7 @@ void cmCursesLongMessageForm::UpdateStatusBar() size = cmCursesMainForm::MAX_WIDTH - 1; } strncpy(bar, this->Title.c_str(), size); - for (size_t i = size - 1; i < cmCursesMainForm::MAX_WIDTH; i++) { + for (size_t i = size; i < cmCursesMainForm::MAX_WIDTH; i++) { bar[i] = ' '; } int width; @@ -89,7 +88,7 @@ void cmCursesLongMessageForm::PrintKeys() return; } char firstLine[512]; - sprintf(firstLine, "Press [e] to exit help"); + sprintf(firstLine, "Press [e] to exit screen"); char fmt_s[] = "%s"; curses_move(y - 2, 0); @@ -112,8 +111,6 @@ void cmCursesLongMessageForm::Render(int /*left*/, int /*top*/, int /*width*/, const char* msg = this->Messages.c_str(); - curses_clear(); - if (this->Fields[0]) { free_field(this->Fields[0]); this->Fields[0] = nullptr; @@ -136,10 +133,13 @@ void cmCursesLongMessageForm::Render(int /*left*/, int /*top*/, int /*width*/, } i++; } - form_driver(this->Form, REQ_BEG_FIELD); + if (this->Scrolling == ScrollBehavior::ScrollDown) { + form_driver(this->Form, REQ_END_FIELD); + } else { + form_driver(this->Form, REQ_BEG_FIELD); + } this->UpdateStatusBar(); - this->PrintKeys(); touchwin(stdscr); refresh(); } @@ -153,6 +153,7 @@ void cmCursesLongMessageForm::HandleInput() char debugMessage[128]; for (;;) { + this->PrintKeys(); int key = getch(); sprintf(debugMessage, "Message widget handling input, key: %d", key); @@ -173,7 +174,6 @@ void cmCursesLongMessageForm::HandleInput() } this->UpdateStatusBar(); - this->PrintKeys(); touchwin(stdscr); wrefresh(stdscr); } diff --git a/Source/CursesDialog/cmCursesLongMessageForm.h b/Source/CursesDialog/cmCursesLongMessageForm.h index 42f9c71..88efe62 100644 --- a/Source/CursesDialog/cmCursesLongMessageForm.h +++ b/Source/CursesDialog/cmCursesLongMessageForm.h @@ -14,8 +14,14 @@ class cmCursesLongMessageForm : public cmCursesForm { public: + enum class ScrollBehavior + { + NoScroll, + ScrollDown + }; + cmCursesLongMessageForm(std::vector<std::string> const& messages, - const char* title); + const char* title, ScrollBehavior scrollBehavior); ~cmCursesLongMessageForm() override; cmCursesLongMessageForm(cmCursesLongMessageForm const&) = delete; @@ -43,6 +49,7 @@ public: protected: std::string Messages; std::string Title; + ScrollBehavior Scrolling; FIELD* Fields[2]; }; diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index 6b71e8a..2c92835 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -34,6 +34,7 @@ cmCursesMainForm::cmCursesMainForm(std::vector<std::string> args, : Args(std::move(args)) , InitialWidth(initWidth) { + this->HasNonStatusOutputs = false; this->NumberOfPages = 0; this->AdvancedMode = false; this->NumberOfVisibleEntries = 0; @@ -321,25 +322,25 @@ void cmCursesMainForm::PrintKeys(int process /* = 0 */) } else { if (this->OkToGenerate) { sprintf(firstLine, - "Press [c] to configure Press [g] to generate and exit"); + " [l] Show log output [c] Configure" + " [g] Generate "); } else { sprintf(firstLine, - "Press [c] to configure "); + " [l] Show log output [c] Configure" + " "); } { const char* toggleKeyInstruction = - "Press [t] to toggle advanced mode (Currently %s)"; + " [t] Toggle advanced mode (currently %s)"; sprintf(thirdLine, toggleKeyInstruction, - this->AdvancedMode ? "On" : "Off"); + this->AdvancedMode ? "on" : "off"); } sprintf(secondLine, - "Press [h] for help " - "Press [q] to quit without generating"); + " [h] Help [q] Quit without generating"); } curses_move(y - 4, 0); - char fmt[512] = - "Press [enter] to edit option Press [d] to delete an entry"; + char fmt[512] = "Keys: [enter] Edit an entry [d] Delete an entry"; if (process) { memset(fmt, ' ', 57); } @@ -364,7 +365,7 @@ void cmCursesMainForm::PrintKeys(int process /* = 0 */) // Print the key of the current entry and the CMake version // on the status bar. Designed for a width of 80 chars. -void cmCursesMainForm::UpdateStatusBar(const char* message) +void cmCursesMainForm::UpdateStatusBar(cm::optional<std::string> message) { int x; int y; @@ -385,119 +386,91 @@ void cmCursesMainForm::UpdateStatusBar(const char* message) return; } - // Get the key of the current entry - FIELD* cur = current_field(this->Form); - int findex = field_index(cur); - cmCursesWidget* lbl = nullptr; - if (findex >= 0) { - lbl = reinterpret_cast<cmCursesWidget*>( - field_userptr(this->Fields[findex - 2])); - } - char help[128] = ""; - const char* curField = ""; - if (lbl) { - curField = lbl->GetValue(); + // Find the current label index + // Field are grouped by 3, the label should be 2 less than the current index + using size_type = decltype(this->Fields)::size_type; + size_type currentLabelIndex = field_index(current_field(this->Form)) - 2; + + // Use the status message if any, otherwise join the key and help string + std::string bar; + if (message) { + bar = *message; + } else { + // Get the key of the current entry + cmCursesWidget* labelWidget = reinterpret_cast<cmCursesWidget*>( + field_userptr(this->Fields[currentLabelIndex])); + std::string labelValue = labelWidget->GetValue(); + bar = labelValue + ": "; // Get the help string of the current entry // and add it to the help string - const char* existingValue = - this->CMakeInstance->GetState()->GetCacheEntryValue(curField); + auto cmakeState = this->CMakeInstance->GetState(); + const char* existingValue = cmakeState->GetCacheEntryValue(labelValue); if (existingValue) { - const char* hs = this->CMakeInstance->GetState()->GetCacheEntryProperty( - curField, "HELPSTRING"); - if (hs) { - strncpy(help, hs, 127); - help[127] = '\0'; - } else { - help[0] = 0; + auto help = cmakeState->GetCacheEntryProperty(labelValue, "HELPSTRING"); + if (help) { + bar += help; } - } else { - sprintf(help, " "); } } + // Pad with spaces to erase any previous text, + // or truncate as necessary to fit the screen + bar.resize(x, ' '); + curses_move(y - 5, 0); + attron(A_STANDOUT); + char fmt_s[] = "%s"; + printw(fmt_s, bar.c_str()); + attroff(A_STANDOUT); - // Join the key, help string and pad with spaces - // (or truncate) as necessary - char bar[cmCursesMainForm::MAX_WIDTH]; - size_t curFieldLen = strlen(curField); - size_t helpLen = strlen(help); - - size_t width = std::min<size_t>(x, cmCursesMainForm::MAX_WIDTH); - - if (message) { - curField = message; - curFieldLen = strlen(message); - strncpy(bar, curField, width); - if (curFieldLen < width) { - memset(bar + curFieldLen, ' ', width - curFieldLen); - } - } else { - strncpy(bar, curField, width); - if (curFieldLen < width) { - bar[curFieldLen] = ':'; - bar[curFieldLen + 1] = ' '; - strncpy(bar + curFieldLen + 2, help, width - curFieldLen - 2); - if (curFieldLen + helpLen + 2 < width) { - memset(bar + curFieldLen + helpLen + 2, ' ', - width - (curFieldLen + helpLen + 2)); - } - } + // Highlight the current label, reset others + // Fields are grouped by 3, the first one being the label + // so start at 0 and move up by 3 avoiding the last null entry + for (size_type index = 0; index < this->Fields.size() - 1; index += 3) { + bool currentLabel = index == currentLabelIndex; + set_field_fore(this->Fields[index], currentLabel ? A_STANDOUT : A_NORMAL); } - bar[width] = '\0'; - - // Display CMake version info on the next line + // Display CMake version under the status bar // We want to display this on the right - char version[cmCursesMainForm::MAX_WIDTH]; - char vertmp[128]; - sprintf(vertmp, "CMake Version %s", cmVersion::GetCMakeVersion()); - size_t sideSpace = (width - strlen(vertmp)); - memset(version, ' ', sideSpace); - sprintf(version + sideSpace, "%s", vertmp); - version[width] = '\0'; - - // Now print both lines - char fmt_s[] = "%s"; - curses_move(y - 5, 0); - attron(A_STANDOUT); - printw(fmt_s, bar); - attroff(A_STANDOUT); - curses_move(y - 4, 0); - printw(fmt_s, version); + std::string version = "CMake Version "; + version += cmVersion::GetCMakeVersion(); + version.resize(std::min<std::string::size_type>(x, version.size())); + curses_move(y - 4, x - static_cast<int>(version.size())); + printw(fmt_s, version.c_str()); + pos_form_cursor(this->Form); } void cmCursesMainForm::UpdateProgress(const std::string& msg, float prog) { - char tmp[1024]; - const char* cmsg = tmp; if (prog >= 0) { - sprintf(tmp, "%s %i%%", msg.c_str(), static_cast<int>(100 * prog)); + constexpr int progressBarWidth = 40; + int progressBarCompleted = static_cast<int>(progressBarWidth * prog); + int percentCompleted = static_cast<int>(100 * prog); + this->LastProgress = (percentCompleted < 100 ? " " : ""); + this->LastProgress += (percentCompleted < 10 ? " " : ""); + this->LastProgress += std::to_string(percentCompleted) + "% ["; + this->LastProgress.append(progressBarCompleted, '#'); + this->LastProgress.append(progressBarWidth - progressBarCompleted, ' '); + this->LastProgress += "] " + msg + "..."; } else { - cmsg = msg.c_str(); + this->Outputs.emplace_back(msg); } - this->UpdateStatusBar(cmsg); - this->PrintKeys(1); - curses_move(1, 1); - touchwin(stdscr); - refresh(); + + this->DisplayOutputs(); } int cmCursesMainForm::Configure(int noconfigure) { - int xi; - int yi; - getmaxyx(stdscr, yi, xi); - - curses_move(1, 1); - this->UpdateStatusBar("Configuring, please wait..."); - this->PrintKeys(1); - touchwin(stdscr); - refresh(); - this->CMakeInstance->SetProgressCallback( - [this](const std::string& msg, float prog) { - this->UpdateProgress(msg, prog); - }); + this->ResetOutputs(); + + if (noconfigure == 0) { + this->UpdateProgress("Configuring", 0); + this->CMakeInstance->SetProgressCallback( + [this](const std::string& msg, float prog) { + this->UpdateProgress(msg, prog); + }); + } // always save the current gui values to disk this->FillCacheManagerFromUI(); @@ -505,9 +478,6 @@ int cmCursesMainForm::Configure(int noconfigure) this->CMakeInstance->GetHomeOutputDirectory()); this->LoadCache(nullptr); - // Get rid of previous errors - this->Errors = std::vector<std::string>(); - // run the generate process this->OkToGenerate = true; int retVal; @@ -524,7 +494,7 @@ int cmCursesMainForm::Configure(int noconfigure) keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ - if (retVal != 0 || !this->Errors.empty()) { + if (retVal != 0 || this->HasNonStatusOutputs) { // see if there was an error if (cmSystemTools::GetErrorOccuredFlag()) { this->OkToGenerate = false; @@ -532,11 +502,13 @@ int cmCursesMainForm::Configure(int noconfigure) int xx; int yy; getmaxyx(stdscr, yy, xx); - cmCursesLongMessageForm* msgs = - new cmCursesLongMessageForm(this->Errors, - cmSystemTools::GetErrorOccuredFlag() - ? "Errors occurred during the last pass." - : "CMake produced the following output."); + const char* title = "Configure produced the following output"; + if (cmSystemTools::GetErrorOccuredFlag()) { + title = "Configure failed with the following output"; + } + cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm( + this->Outputs, title, + cmCursesLongMessageForm::ScrollBehavior::ScrollDown); // reset error condition cmSystemTools::ResetErrorOccuredFlag(); CurrentForm = msgs; @@ -547,11 +519,13 @@ int cmCursesMainForm::Configure(int noconfigure) if (retVal == -2) { return retVal; } - CurrentForm = this; - this->Render(1, 1, xx, yy); } this->InitializeUI(); + CurrentForm = this; + int xi; + int yi; + getmaxyx(stdscr, yi, xi); this->Render(1, 1, xi, yi); return 0; @@ -559,30 +533,21 @@ int cmCursesMainForm::Configure(int noconfigure) int cmCursesMainForm::Generate() { - int xi; - int yi; - getmaxyx(stdscr, yi, xi); + this->ResetOutputs(); - curses_move(1, 1); - this->UpdateStatusBar("Generating, please wait..."); - this->PrintKeys(1); - touchwin(stdscr); - refresh(); + this->UpdateProgress("Generating", 0); this->CMakeInstance->SetProgressCallback( [this](const std::string& msg, float prog) { this->UpdateProgress(msg, prog); }); - // Get rid of previous errors - this->Errors = std::vector<std::string>(); - // run the generate process int retVal = this->CMakeInstance->Generate(); this->CMakeInstance->SetProgressCallback(nullptr); keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ - if (retVal != 0 || !this->Errors.empty()) { + if (retVal != 0 || this->HasNonStatusOutputs) { // see if there was an error if (cmSystemTools::GetErrorOccuredFlag()) { this->OkToGenerate = false; @@ -592,12 +557,13 @@ int cmCursesMainForm::Generate() int xx; int yy; getmaxyx(stdscr, yy, xx); - const char* title = "Messages during last pass."; + const char* title = "Generate produced the following output"; if (cmSystemTools::GetErrorOccuredFlag()) { - title = "Errors occurred during the last pass."; + title = "Generate failed with the following output"; } - cmCursesLongMessageForm* msgs = - new cmCursesLongMessageForm(this->Errors, title); + cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm( + this->Outputs, title, + cmCursesLongMessageForm::ScrollBehavior::ScrollDown); CurrentForm = msgs; msgs->Render(1, 1, xx, yy); msgs->HandleInput(); @@ -606,11 +572,13 @@ int cmCursesMainForm::Generate() if (retVal == -2) { return retVal; } - CurrentForm = this; - this->Render(1, 1, xx, yy); } this->InitializeUI(); + CurrentForm = this; + int xi; + int yi; + getmaxyx(stdscr, yi, xi); this->Render(1, 1, xi, yi); return 0; @@ -619,7 +587,9 @@ int cmCursesMainForm::Generate() void cmCursesMainForm::AddError(const std::string& message, const char* /*unused*/) { - this->Errors.emplace_back(message); + this->Outputs.emplace_back(message); + this->HasNonStatusOutputs = true; + this->DisplayOutputs(); } void cmCursesMainForm::RemoveEntry(const char* value) @@ -704,7 +674,7 @@ void cmCursesMainForm::HandleInput() this->PrintKeys(); if (this->SearchMode) { std::string searchstr = "Search: " + this->SearchString; - this->UpdateStatusBar(searchstr.c_str()); + this->UpdateStatusBar(searchstr); this->PrintKeys(1); curses_move(y - 5, static_cast<unsigned int>(searchstr.size())); // curses_move(1,1); @@ -848,8 +818,9 @@ void cmCursesMainForm::HandleInput() this->HelpMessage[1] = ""; } - cmCursesLongMessageForm* msgs = - new cmCursesLongMessageForm(this->HelpMessage, "Help."); + cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm( + this->HelpMessage, "Help", + cmCursesLongMessageForm::ScrollBehavior::NoScroll); CurrentForm = msgs; msgs->Render(1, 1, x, y); msgs->HandleInput(); @@ -861,7 +832,8 @@ void cmCursesMainForm::HandleInput() else if (key == 'l') { getmaxyx(stdscr, y, x); cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm( - this->Errors, "Errors occurred during the last pass."); + this->Outputs, "CMake produced the following output", + cmCursesLongMessageForm::ScrollBehavior::NoScroll); CurrentForm = msgs; msgs->Render(1, 1, x, y); msgs->HandleInput(); @@ -1007,15 +979,6 @@ void cmCursesMainForm::JumpToCacheEntry(const char* astr) } else { form_driver(this->Form, REQ_NEXT_FIELD); } - /* - char buffer[1024]; - sprintf(buffer, "Line: %d != %d / %d\n", findex, idx, - this->NumberOfVisibleEntries); - touchwin(stdscr); - refresh(); - this->UpdateStatusBar( buffer ); - usleep(100000); - */ cur = current_field(this->Form); findex = field_index(cur); if (findex == start_index) { @@ -1024,6 +987,28 @@ void cmCursesMainForm::JumpToCacheEntry(const char* astr) } } +void cmCursesMainForm::ResetOutputs() +{ + this->LogForm.reset(); + this->Outputs.clear(); + this->HasNonStatusOutputs = false; + this->LastProgress.clear(); +} + +void cmCursesMainForm::DisplayOutputs() +{ + int xi; + int yi; + getmaxyx(stdscr, yi, xi); + + auto newLogForm = new cmCursesLongMessageForm( + this->Outputs, this->LastProgress.c_str(), + cmCursesLongMessageForm::ScrollBehavior::ScrollDown); + CurrentForm = newLogForm; + this->LogForm.reset(newLogForm); + this->LogForm->Render(1, 1, xi, yi); +} + const char* cmCursesMainForm::s_ConstHelpMessage = "CMake is used to configure and generate build files for software projects. " "The basic steps for configuring a project with ccmake are as follows:\n\n" @@ -1080,7 +1065,7 @@ const char* cmCursesMainForm::s_ConstHelpMessage = " c : process the configuration files with the current options\n" " g : generate build files and exit, only available when there are no " "new options and no errors have been detected during last configuration.\n" - " l : shows last errors\n" + " l : shows cmake output\n" " d : delete an option\n" " t : toggles advanced mode. In normal mode, only the most important " "options are shown. In advanced mode, all options are shown. We recommend " diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h index b8769b7..b7c204d 100644 --- a/Source/CursesDialog/cmCursesMainForm.h +++ b/Source/CursesDialog/cmCursesMainForm.h @@ -10,12 +10,15 @@ #include <string> #include <vector> +#include <cm/optional> + #include "cmCursesCacheEntryComposite.h" #include "cmCursesForm.h" #include "cmCursesStandardIncludes.h" #include "cmStateTypes.h" class cmake; +class cmCursesLongMessageForm; /** \class cmCursesMainForm * \brief The main page of ccmake @@ -66,8 +69,8 @@ public: * exception is during a resize. The optional argument specifies the * string to be displayed in the status bar. */ - void UpdateStatusBar() override { this->UpdateStatusBar(nullptr); } - virtual void UpdateStatusBar(const char* message); + void UpdateStatusBar() override { this->UpdateStatusBar(cm::nullopt); } + void UpdateStatusBar(cm::optional<std::string> message); /** * Display current commands and their keys on the toolbar. This @@ -122,10 +125,24 @@ protected: // Jump to the cache entry whose name matches the string. void JumpToCacheEntry(const char* str); + // Clear and reset the output log and state + void ResetOutputs(); + + // Display the current progress and output + void DisplayOutputs(); + // Copies of cache entries stored in the user interface std::vector<cmCursesCacheEntryComposite> Entries; - // Errors produced during last run of cmake - std::vector<std::string> Errors; + + // The form used to display logs during processing + std::unique_ptr<cmCursesLongMessageForm> LogForm; + // Output produced by the last pass + std::vector<std::string> Outputs; + // Did the last pass produced outputs of interest (errors, warnings, ...) + bool HasNonStatusOutputs; + // Last progress bar + std::string LastProgress; + // Command line arguments to be passed to cmake each time // it is run std::vector<std::string> Args; diff --git a/Source/CursesDialog/cmCursesOptionsWidget.cxx b/Source/CursesDialog/cmCursesOptionsWidget.cxx index eb773ad..a15241f 100644 --- a/Source/CursesDialog/cmCursesOptionsWidget.cxx +++ b/Source/CursesDialog/cmCursesOptionsWidget.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCursesOptionsWidget.h" +#include "cmCursesColor.h" #include "cmCursesWidget.h" #include "cmStateTypes.h" @@ -15,8 +16,13 @@ cmCursesOptionsWidget::cmCursesOptionsWidget(int width, int height, int left, // there is no option type, and string type causes ccmake to cast // the widget into a string widget at some point. BOOL is safe for // now. - set_field_fore(this->Field, A_NORMAL); - set_field_back(this->Field, A_STANDOUT); + if (cmCursesColor::HasColors()) { + set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Options)); + set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Options)); + } else { + set_field_fore(this->Field, A_NORMAL); + set_field_back(this->Field, A_STANDOUT); + } field_opts_off(this->Field, O_STATIC); } diff --git a/Source/CursesDialog/cmCursesPathWidget.cxx b/Source/CursesDialog/cmCursesPathWidget.cxx index bb3808e..8ed42de 100644 --- a/Source/CursesDialog/cmCursesPathWidget.cxx +++ b/Source/CursesDialog/cmCursesPathWidget.cxx @@ -4,6 +4,7 @@ #include <vector> +#include "cmCursesColor.h" #include "cmCursesMainForm.h" #include "cmCursesStringWidget.h" #include "cmStateTypes.h" @@ -16,6 +17,13 @@ cmCursesPathWidget::cmCursesPathWidget(int width, int height, int left, this->Type = cmStateEnums::PATH; this->Cycle = false; this->CurrentIndex = 0; + if (cmCursesColor::HasColors()) { + set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Path)); + set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Path)); + } else { + set_field_fore(this->Field, A_NORMAL); + set_field_back(this->Field, A_STANDOUT); + } } void cmCursesPathWidget::OnType(int& key, cmCursesMainForm* fm, WINDOW* w) diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx index 6296af2..c629478 100644 --- a/Source/CursesDialog/cmCursesStringWidget.cxx +++ b/Source/CursesDialog/cmCursesStringWidget.cxx @@ -4,6 +4,7 @@ #include <cstdio> +#include "cmCursesColor.h" #include "cmCursesForm.h" #include "cmCursesMainForm.h" #include "cmCursesStandardIncludes.h" @@ -21,8 +22,13 @@ cmCursesStringWidget::cmCursesStringWidget(int width, int height, int left, { this->InEdit = false; this->Type = cmStateEnums::STRING; - set_field_fore(this->Field, A_NORMAL); - set_field_back(this->Field, A_STANDOUT); + if (cmCursesColor::HasColors()) { + set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::String)); + set_field_back(this->Field, COLOR_PAIR(cmCursesColor::String)); + } else { + set_field_fore(this->Field, A_NORMAL); + set_field_back(this->Field, A_STANDOUT); + } field_opts_off(this->Field, O_STATIC); } diff --git a/Source/LexerParser/.gitattributes b/Source/LexerParser/.gitattributes index bf70249..63d9afb 100644 --- a/Source/LexerParser/.gitattributes +++ b/Source/LexerParser/.gitattributes @@ -16,4 +16,6 @@ /cmFortranLexer.h generated /cmFortranParser.cxx generated /cmFortranParserTokens.h generated +/cmGccDepfileLexer.cxx generated +/cmGccDepfileLexer.h generated /cmListFileLexer.c generated diff --git a/Source/LexerParser/cmCommandArgumentParser.cxx b/Source/LexerParser/cmCommandArgumentParser.cxx index ae7fb42..34dc8ec 100644 --- a/Source/LexerParser/cmCommandArgumentParser.cxx +++ b/Source/LexerParser/cmCommandArgumentParser.cxx @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.3.2. */ +/* A Bison parser, made by GNU Bison 3.4.2. */ /* Bison implementation for Yacc-like parsers in C @@ -48,7 +48,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.3.2" +#define YYBISON_VERSION "3.4.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -72,7 +72,7 @@ /* First part of user prologue. */ -#line 1 "cmCommandArgumentParser.y" /* yacc.c:337 */ +#line 1 "cmCommandArgumentParser.y" /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ @@ -134,7 +134,8 @@ static void cmCommandArgument_yyerror(yyscan_t yyscanner, const char* message); # pragma GCC diagnostic ignored "-Wconversion" #endif -#line 138 "cmCommandArgumentParser.cxx" /* yacc.c:337 */ +#line 138 "cmCommandArgumentParser.cxx" + # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus @@ -155,8 +156,8 @@ static void cmCommandArgument_yyerror(yyscan_t yyscanner, const char* message); # define YYERROR_VERBOSE 1 #endif -/* In a future release of Bison, this section will be replaced - by #include "cmCommandArgumentParserTokens.h". */ +/* Use api.header.include to #include this header + instead of duplicating it here. */ #ifndef YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED # define YY_CMCOMMANDARGUMENT_YY_CMCOMMANDARGUMENTPARSERTOKENS_H_INCLUDED /* Debug traces. */ @@ -310,6 +311,8 @@ typedef short yytype_int16; #endif +#define YY_ASSERT(E) ((void) (0 && (E))) + #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ @@ -700,7 +703,9 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy if (yytype < YYNTOKENS) YYPRINT (yyo, yytoknum[yytype], *yyvaluep); # endif + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -1138,6 +1143,8 @@ yynewstate: | yynewstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); *yyssp = (yytype_int16) yystate; if (yyss + yystacksize - 1 <= yyssp) @@ -1200,8 +1207,6 @@ yysetstate: } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - if (yystate == YYFINAL) YYACCEPT; @@ -1269,7 +1274,6 @@ yybackup: YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END - goto yynewstate; @@ -1304,193 +1308,194 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 2: -#line 99 "cmCommandArgumentParser.y" /* yacc.c:1652 */ + case 2: +#line 99 "cmCommandArgumentParser.y" { (yyval.str) = 0; yyGetParser->SetResult((yyvsp[0].str)); } -#line 1314 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1318 "cmCommandArgumentParser.cxx" break; case 3: -#line 105 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 105 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1322 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1326 "cmCommandArgumentParser.cxx" break; case 4: -#line 108 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 108 "cmCommandArgumentParser.y" { (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str)); } -#line 1330 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1334 "cmCommandArgumentParser.cxx" break; case 5: -#line 113 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 113 "cmCommandArgumentParser.y" { (yyval.str) = 0; } -#line 1338 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1342 "cmCommandArgumentParser.cxx" break; case 6: -#line 116 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 116 "cmCommandArgumentParser.y" { (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str)); } -#line 1346 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1350 "cmCommandArgumentParser.cxx" break; case 7: -#line 121 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 121 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1354 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1358 "cmCommandArgumentParser.cxx" break; case 8: -#line 124 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 124 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1362 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1366 "cmCommandArgumentParser.cxx" break; case 9: -#line 129 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 129 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1370 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1374 "cmCommandArgumentParser.cxx" break; case 10: -#line 132 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 132 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1378 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1382 "cmCommandArgumentParser.cxx" break; case 11: -#line 135 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 135 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1386 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1390 "cmCommandArgumentParser.cxx" break; case 12: -#line 138 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 138 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1394 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1398 "cmCommandArgumentParser.cxx" break; case 13: -#line 141 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 141 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1402 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1406 "cmCommandArgumentParser.cxx" break; case 14: -#line 144 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 144 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1410 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1414 "cmCommandArgumentParser.cxx" break; case 15: -#line 149 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 149 "cmCommandArgumentParser.y" { (yyval.str) = yyGetParser->ExpandSpecialVariable((yyvsp[-2].str), (yyvsp[-1].str)); } -#line 1418 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1422 "cmCommandArgumentParser.cxx" break; case 16: -#line 152 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 152 "cmCommandArgumentParser.y" { (yyval.str) = yyGetParser->ExpandSpecialVariable((yyvsp[-2].str), (yyvsp[-1].str)); } -#line 1426 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1430 "cmCommandArgumentParser.cxx" break; case 17: -#line 155 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 155 "cmCommandArgumentParser.y" { (yyval.str) = yyGetParser->ExpandVariable((yyvsp[-1].str)); } -#line 1434 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1438 "cmCommandArgumentParser.cxx" break; case 18: -#line 158 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 158 "cmCommandArgumentParser.y" { (yyval.str) = yyGetParser->ExpandVariableForAt((yyvsp[0].str)); } -#line 1442 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1446 "cmCommandArgumentParser.cxx" break; case 19: -#line 163 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 163 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1450 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1454 "cmCommandArgumentParser.cxx" break; case 20: -#line 166 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 166 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[-1].str); } -#line 1458 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1462 "cmCommandArgumentParser.cxx" break; case 21: -#line 171 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 171 "cmCommandArgumentParser.y" { (yyval.str) = 0; } -#line 1466 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1470 "cmCommandArgumentParser.cxx" break; case 22: -#line 174 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 174 "cmCommandArgumentParser.y" { (yyval.str) = yyGetParser->CombineUnions((yyvsp[-1].str), (yyvsp[0].str)); } -#line 1474 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1478 "cmCommandArgumentParser.cxx" break; case 23: -#line 179 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 179 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1482 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1486 "cmCommandArgumentParser.cxx" break; case 24: -#line 182 "cmCommandArgumentParser.y" /* yacc.c:1652 */ +#line 182 "cmCommandArgumentParser.y" { (yyval.str) = (yyvsp[0].str); } -#line 1490 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1494 "cmCommandArgumentParser.cxx" break; -#line 1494 "cmCommandArgumentParser.cxx" /* yacc.c:1652 */ +#line 1498 "cmCommandArgumentParser.cxx" + default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1723,7 +1728,7 @@ yyreturn: #endif return yyresult; } -#line 187 "cmCommandArgumentParser.y" /* yacc.c:1918 */ +#line 187 "cmCommandArgumentParser.y" /* End of grammar */ diff --git a/Source/LexerParser/cmCommandArgumentParserTokens.h b/Source/LexerParser/cmCommandArgumentParserTokens.h index 56c9794..033b899 100644 --- a/Source/LexerParser/cmCommandArgumentParserTokens.h +++ b/Source/LexerParser/cmCommandArgumentParserTokens.h @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.3.2. */ +/* A Bison parser, made by GNU Bison 3.4.2. */ /* Bison interface for Yacc-like parsers in C diff --git a/Source/LexerParser/cmDependsJavaParser.cxx b/Source/LexerParser/cmDependsJavaParser.cxx index 6c1fb2c..b15082d 100644 --- a/Source/LexerParser/cmDependsJavaParser.cxx +++ b/Source/LexerParser/cmDependsJavaParser.cxx @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.3.2. */ +/* A Bison parser, made by GNU Bison 3.4.2. */ /* Bison implementation for Yacc-like parsers in C @@ -48,7 +48,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.3.2" +#define YYBISON_VERSION "3.4.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -72,7 +72,7 @@ /* First part of user prologue. */ -#line 1 "cmDependsJavaParser.y" /* yacc.c:337 */ +#line 1 "cmDependsJavaParser.y" /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ @@ -123,7 +123,8 @@ static void cmDependsJava_yyerror(yyscan_t yyscanner, const char* message); # pragma GCC diagnostic ignored "-Wconversion" #endif -#line 127 "cmDependsJavaParser.cxx" /* yacc.c:337 */ +#line 127 "cmDependsJavaParser.cxx" + # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus @@ -144,8 +145,8 @@ static void cmDependsJava_yyerror(yyscan_t yyscanner, const char* message); # define YYERROR_VERBOSE 1 #endif -/* In a future release of Bison, this section will be replaced - by #include "cmDependsJavaParserTokens.h". */ +/* Use api.header.include to #include this header + instead of duplicating it here. */ #ifndef YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED # define YY_CMDEPENDSJAVA_YY_CMDEPENDSJAVAPARSERTOKENS_H_INCLUDED /* Debug traces. */ @@ -481,6 +482,8 @@ typedef short yytype_int16; #endif +#define YY_ASSERT(E) ((void) (0 && (E))) + #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ @@ -1685,7 +1688,9 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy if (yytype < YYNTOKENS) YYPRINT (yyo, yytoknum[yytype], *yyvaluep); # endif + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -2123,6 +2128,8 @@ yynewstate: | yynewstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); *yyssp = (yytype_int16) yystate; if (yyss + yystacksize - 1 <= yyssp) @@ -2185,8 +2192,6 @@ yysetstate: } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - if (yystate == YYFINAL) YYACCEPT; @@ -2254,7 +2259,6 @@ yybackup: YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END - goto yynewstate; @@ -2289,215 +2293,215 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 2: -#line 183 "cmDependsJavaParser.y" /* yacc.c:1652 */ + case 2: +#line 183 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2301 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2305 "cmDependsJavaParser.cxx" break; case 3: -#line 192 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 192 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2312 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2316 "cmDependsJavaParser.cxx" break; case 4: -#line 200 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 200 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2323 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2327 "cmDependsJavaParser.cxx" break; case 5: -#line 208 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 208 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2334 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2338 "cmDependsJavaParser.cxx" break; case 6: -#line 216 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 216 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2345 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2349 "cmDependsJavaParser.cxx" break; case 7: -#line 224 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 224 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2356 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2360 "cmDependsJavaParser.cxx" break; case 8: -#line 232 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 232 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2367 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2371 "cmDependsJavaParser.cxx" break; case 9: -#line 241 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 241 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2378 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2382 "cmDependsJavaParser.cxx" break; case 10: -#line 249 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 249 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2389 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2393 "cmDependsJavaParser.cxx" break; case 11: -#line 258 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 258 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2400 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2404 "cmDependsJavaParser.cxx" break; case 12: -#line 266 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 266 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2411 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2415 "cmDependsJavaParser.cxx" break; case 13: -#line 275 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 275 "cmDependsJavaParser.y" { jpElementStart(0); } -#line 2419 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2423 "cmDependsJavaParser.cxx" break; case 14: -#line 280 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 280 "cmDependsJavaParser.y" { jpElementStart(0); } -#line 2427 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2431 "cmDependsJavaParser.cxx" break; case 15: -#line 285 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 285 "cmDependsJavaParser.y" { jpElementStart(0); } -#line 2435 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2439 "cmDependsJavaParser.cxx" break; case 16: -#line 290 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 290 "cmDependsJavaParser.y" { jpElementStart(0); } -#line 2443 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2447 "cmDependsJavaParser.cxx" break; case 17: -#line 295 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 295 "cmDependsJavaParser.y" { jpElementStart(0); } -#line 2451 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2455 "cmDependsJavaParser.cxx" break; case 18: -#line 300 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 300 "cmDependsJavaParser.y" { jpElementStart(0); } -#line 2459 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2463 "cmDependsJavaParser.cxx" break; case 19: -#line 305 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 305 "cmDependsJavaParser.y" { jpElementStart(0); } -#line 2467 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2471 "cmDependsJavaParser.cxx" break; case 20: -#line 310 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 310 "cmDependsJavaParser.y" { jpElementStart(0); } -#line 2475 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2479 "cmDependsJavaParser.cxx" break; case 21: -#line 316 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 316 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2486 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2490 "cmDependsJavaParser.cxx" break; case 22: -#line 324 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 324 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2497 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2501 "cmDependsJavaParser.cxx" break; case 23: -#line 333 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 333 "cmDependsJavaParser.y" { jpElementStart(1); jpStoreClass((yyvsp[0].str)); @@ -2505,44 +2509,44 @@ yyreduce: (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2509 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2513 "cmDependsJavaParser.cxx" break; case 24: -#line 343 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 343 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2520 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2524 "cmDependsJavaParser.cxx" break; case 25: -#line 352 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 352 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2531 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2535 "cmDependsJavaParser.cxx" break; case 26: -#line 361 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 361 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2542 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2546 "cmDependsJavaParser.cxx" break; case 27: -#line 369 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 369 "cmDependsJavaParser.y" { jpElementStart(2); jpStoreClass((yyvsp[-1].str)); @@ -2550,56 +2554,56 @@ yyreduce: (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2554 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2558 "cmDependsJavaParser.cxx" break; case 28: -#line 379 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 379 "cmDependsJavaParser.y" { jpElementStart(1); (yyval.str) = (yyvsp[0].str); } -#line 2563 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2567 "cmDependsJavaParser.cxx" break; case 29: -#line 385 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 385 "cmDependsJavaParser.y" { jpElementStart(1); (yyval.str) = (yyvsp[0].str); } -#line 2572 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2576 "cmDependsJavaParser.cxx" break; case 30: -#line 392 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 392 "cmDependsJavaParser.y" { jpElementStart(1); (yyval.str) = (yyvsp[0].str); } -#line 2581 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2585 "cmDependsJavaParser.cxx" break; case 31: -#line 399 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 399 "cmDependsJavaParser.y" { jpElementStart(1); (yyval.str) = (yyvsp[0].str); } -#line 2590 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2594 "cmDependsJavaParser.cxx" break; case 32: -#line 405 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 405 "cmDependsJavaParser.y" { jpElementStart(2); (yyval.str) = (yyvsp[0].str); } -#line 2599 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2603 "cmDependsJavaParser.cxx" break; case 33: -#line 412 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 412 "cmDependsJavaParser.y" { jpElementStart(3); yyGetParser->AddClassFound((yyvsp[-2].str)); @@ -2607,11 +2611,11 @@ yyreduce: yyGetParser->DeallocateParserType(&((yyvsp[-2].str))); (yyval.str) = const_cast<char*>(yyGetParser->GetCurrentCombine()); } -#line 2611 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2615 "cmDependsJavaParser.cxx" break; case 34: -#line 421 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 421 "cmDependsJavaParser.y" { jpElementStart(3); jpStoreClass((yyvsp[-2].str)); @@ -2620,11 +2624,11 @@ yyreduce: (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2624 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2628 "cmDependsJavaParser.cxx" break; case 35: -#line 431 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 431 "cmDependsJavaParser.y" { jpElementStart(3); jpStoreClass((yyvsp[-2].str)); @@ -2633,118 +2637,118 @@ yyreduce: (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2637 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2641 "cmDependsJavaParser.cxx" break; case 36: -#line 441 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 441 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2648 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2652 "cmDependsJavaParser.cxx" break; case 37: -#line 450 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 450 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2659 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2663 "cmDependsJavaParser.cxx" break; case 38: -#line 458 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 458 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2670 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2674 "cmDependsJavaParser.cxx" break; case 39: -#line 467 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 467 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2681 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2685 "cmDependsJavaParser.cxx" break; case 40: -#line 475 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 475 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2691 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2695 "cmDependsJavaParser.cxx" break; case 41: -#line 482 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 482 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2702 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2706 "cmDependsJavaParser.cxx" break; case 42: -#line 490 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 490 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2712 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2716 "cmDependsJavaParser.cxx" break; case 43: -#line 497 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 497 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2723 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2727 "cmDependsJavaParser.cxx" break; case 44: -#line 505 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 505 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2733 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2737 "cmDependsJavaParser.cxx" break; case 45: -#line 512 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 512 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2744 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2748 "cmDependsJavaParser.cxx" break; case 46: -#line 521 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 521 "cmDependsJavaParser.y" { jpElementStart(3); yyGetParser->SetCurrentPackage((yyvsp[-1].str)); @@ -2754,33 +2758,33 @@ yyreduce: (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2758 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2762 "cmDependsJavaParser.cxx" break; case 47: -#line 533 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 533 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2769 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2773 "cmDependsJavaParser.cxx" break; case 48: -#line 541 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 541 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2780 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2784 "cmDependsJavaParser.cxx" break; case 49: -#line 550 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 550 "cmDependsJavaParser.y" { jpElementStart(3); yyGetParser->AddPackagesImport((yyvsp[-1].str)); @@ -2790,11 +2794,11 @@ yyreduce: (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2794 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2798 "cmDependsJavaParser.cxx" break; case 50: -#line 562 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 562 "cmDependsJavaParser.y" { jpElementStart(5); std::string str = (yyvsp[-3].str); @@ -2805,77 +2809,77 @@ yyreduce: (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2809 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2813 "cmDependsJavaParser.cxx" break; case 51: -#line 575 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 575 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2820 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2824 "cmDependsJavaParser.cxx" break; case 52: -#line 583 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 583 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2831 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2835 "cmDependsJavaParser.cxx" break; case 53: -#line 591 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 591 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2842 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2846 "cmDependsJavaParser.cxx" break; case 54: -#line 600 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 600 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2853 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2857 "cmDependsJavaParser.cxx" break; case 55: -#line 608 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 608 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2864 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2868 "cmDependsJavaParser.cxx" break; case 67: -#line 623 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 623 "cmDependsJavaParser.y" { yyGetParser->StartClass((yyvsp[0].str)); jpElementStart(3); yyGetParser->DeallocateParserType(&((yyvsp[0].str))); jpCheckEmpty(3); } -#line 2875 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2879 "cmDependsJavaParser.cxx" break; case 68: -#line 633 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 633 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -2883,11 +2887,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); yyGetParser->EndClass(); } -#line 2887 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2891 "cmDependsJavaParser.cxx" break; case 69: -#line 642 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 642 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(2); @@ -2895,11 +2899,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); yyGetParser->EndClass(); } -#line 2899 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2903 "cmDependsJavaParser.cxx" break; case 70: -#line 651 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 651 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -2907,11 +2911,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); yyGetParser->EndClass(); } -#line 2911 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2915 "cmDependsJavaParser.cxx" break; case 71: -#line 660 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 660 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -2919,226 +2923,226 @@ yyreduce: yyGetParser->SetCurrentCombine(""); yyGetParser->EndClass(); } -#line 2923 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2927 "cmDependsJavaParser.cxx" break; case 72: -#line 669 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 669 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2933 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2937 "cmDependsJavaParser.cxx" break; case 73: -#line 676 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 676 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2944 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2948 "cmDependsJavaParser.cxx" break; case 74: -#line 685 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 685 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2955 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2959 "cmDependsJavaParser.cxx" break; case 75: -#line 694 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 694 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2966 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2970 "cmDependsJavaParser.cxx" break; case 76: -#line 703 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 703 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2977 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2981 "cmDependsJavaParser.cxx" break; case 77: -#line 711 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 711 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2988 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 2992 "cmDependsJavaParser.cxx" break; case 78: -#line 720 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 720 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 2999 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3003 "cmDependsJavaParser.cxx" break; case 79: -#line 728 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 728 "cmDependsJavaParser.y" { jpElementStart(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3009 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3013 "cmDependsJavaParser.cxx" break; case 80: -#line 735 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 735 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3020 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3024 "cmDependsJavaParser.cxx" break; case 81: -#line 744 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 744 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3031 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3035 "cmDependsJavaParser.cxx" break; case 82: -#line 752 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 752 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3042 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3046 "cmDependsJavaParser.cxx" break; case 83: -#line 760 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 760 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3053 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3057 "cmDependsJavaParser.cxx" break; case 84: -#line 768 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 768 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3064 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3068 "cmDependsJavaParser.cxx" break; case 85: -#line 777 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 777 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3075 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3079 "cmDependsJavaParser.cxx" break; case 86: -#line 785 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 785 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3086 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3090 "cmDependsJavaParser.cxx" break; case 87: -#line 794 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 794 "cmDependsJavaParser.y" { jpElementStart(4); } -#line 3094 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3098 "cmDependsJavaParser.cxx" break; case 88: -#line 800 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 800 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3105 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3109 "cmDependsJavaParser.cxx" break; case 89: -#line 808 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 808 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3116 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3120 "cmDependsJavaParser.cxx" break; case 90: -#line 817 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 817 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3127 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3131 "cmDependsJavaParser.cxx" break; case 91: -#line 825 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 825 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3138 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3142 "cmDependsJavaParser.cxx" break; case 92: -#line 834 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 834 "cmDependsJavaParser.y" { jpElementStart(1); yyGetParser->DeallocateParserType(&((yyvsp[0].str))); @@ -3146,77 +3150,77 @@ yyreduce: (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3150 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3154 "cmDependsJavaParser.cxx" break; case 93: -#line 843 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 843 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3161 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3165 "cmDependsJavaParser.cxx" break; case 94: -#line 852 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 852 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3172 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3176 "cmDependsJavaParser.cxx" break; case 95: -#line 860 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 860 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3183 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3187 "cmDependsJavaParser.cxx" break; case 96: -#line 869 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 869 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3194 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3198 "cmDependsJavaParser.cxx" break; case 97: -#line 877 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 877 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3205 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3209 "cmDependsJavaParser.cxx" break; case 98: -#line 885 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 885 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3216 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3220 "cmDependsJavaParser.cxx" break; case 99: -#line 894 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 894 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -3224,11 +3228,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3228 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3232 "cmDependsJavaParser.cxx" break; case 100: -#line 903 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 903 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -3236,22 +3240,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3240 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3244 "cmDependsJavaParser.cxx" break; case 101: -#line 912 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 912 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3251 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3255 "cmDependsJavaParser.cxx" break; case 102: -#line 920 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 920 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3259,11 +3263,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3263 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3267 "cmDependsJavaParser.cxx" break; case 103: -#line 930 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 930 "cmDependsJavaParser.y" { jpElementStart(4); yyGetParser->DeallocateParserType(&((yyvsp[-3].str))); @@ -3272,40 +3276,40 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3276 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3280 "cmDependsJavaParser.cxx" break; case 104: -#line 940 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 940 "cmDependsJavaParser.y" { jpElementStart(3); } -#line 3285 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3289 "cmDependsJavaParser.cxx" break; case 105: -#line 946 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 946 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3296 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3300 "cmDependsJavaParser.cxx" break; case 107: -#line 957 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 957 "cmDependsJavaParser.y" { jpElementStart(1); } -#line 3305 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3309 "cmDependsJavaParser.cxx" break; case 108: -#line 963 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 963 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -3313,11 +3317,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3317 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3321 "cmDependsJavaParser.cxx" break; case 109: -#line 973 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 973 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -3325,11 +3329,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3329 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3333 "cmDependsJavaParser.cxx" break; case 110: -#line 983 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 983 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -3337,20 +3341,20 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3341 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3345 "cmDependsJavaParser.cxx" break; case 111: -#line 993 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 993 "cmDependsJavaParser.y" { jpElementStart(1); } -#line 3350 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3354 "cmDependsJavaParser.cxx" break; case 112: -#line 999 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 999 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -3358,11 +3362,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3362 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3366 "cmDependsJavaParser.cxx" break; case 113: -#line 1009 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1009 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3370,11 +3374,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3374 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3378 "cmDependsJavaParser.cxx" break; case 114: -#line 1019 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1019 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -3382,11 +3386,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3386 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3390 "cmDependsJavaParser.cxx" break; case 115: -#line 1029 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1029 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -3394,11 +3398,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3398 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3402 "cmDependsJavaParser.cxx" break; case 116: -#line 1038 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1038 "cmDependsJavaParser.y" { jpElementStart(5); jpCheckEmpty(5); @@ -3406,11 +3410,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3410 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3414 "cmDependsJavaParser.cxx" break; case 117: -#line 1048 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1048 "cmDependsJavaParser.y" { jpElementStart(4); yyGetParser->DeallocateParserType(&((yyvsp[-3].str))); @@ -3419,11 +3423,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3423 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3427 "cmDependsJavaParser.cxx" break; case 118: -#line 1059 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1059 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -3431,22 +3435,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3435 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3439 "cmDependsJavaParser.cxx" break; case 119: -#line 1068 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1068 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3446 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3450 "cmDependsJavaParser.cxx" break; case 120: -#line 1076 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1076 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -3454,11 +3458,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3458 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3462 "cmDependsJavaParser.cxx" break; case 121: -#line 1086 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1086 "cmDependsJavaParser.y" { jpElementStart(5); jpCheckEmpty(5); @@ -3466,11 +3470,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3470 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3474 "cmDependsJavaParser.cxx" break; case 122: -#line 1095 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1095 "cmDependsJavaParser.y" { jpElementStart(5); jpCheckEmpty(5); @@ -3478,22 +3482,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3482 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3486 "cmDependsJavaParser.cxx" break; case 123: -#line 1105 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1105 "cmDependsJavaParser.y" { yyGetParser->StartClass((yyvsp[0].str)); jpElementStart(3); yyGetParser->DeallocateParserType(&((yyvsp[0].str))); jpCheckEmpty(3); } -#line 3493 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3497 "cmDependsJavaParser.cxx" break; case 124: -#line 1114 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1114 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -3501,21 +3505,21 @@ yyreduce: yyGetParser->SetCurrentCombine(""); yyGetParser->EndClass(); } -#line 3505 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3509 "cmDependsJavaParser.cxx" break; case 125: -#line 1123 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1123 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3515 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3519 "cmDependsJavaParser.cxx" break; case 126: -#line 1130 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1130 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3523,11 +3527,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3527 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3531 "cmDependsJavaParser.cxx" break; case 127: -#line 1140 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1140 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -3535,11 +3539,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3539 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3543 "cmDependsJavaParser.cxx" break; case 128: -#line 1149 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1149 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -3547,11 +3551,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3551 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3555 "cmDependsJavaParser.cxx" break; case 129: -#line 1159 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1159 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -3559,33 +3563,33 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3563 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3567 "cmDependsJavaParser.cxx" break; case 130: -#line 1168 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1168 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3574 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3578 "cmDependsJavaParser.cxx" break; case 131: -#line 1176 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1176 "cmDependsJavaParser.y" { jpElementStart(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3585 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3589 "cmDependsJavaParser.cxx" break; case 132: -#line 1185 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1185 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3593,11 +3597,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3597 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3601 "cmDependsJavaParser.cxx" break; case 133: -#line 1194 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1194 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3605,11 +3609,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3609 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3613 "cmDependsJavaParser.cxx" break; case 134: -#line 1203 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1203 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3617,22 +3621,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3621 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3625 "cmDependsJavaParser.cxx" break; case 135: -#line 1212 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1212 "cmDependsJavaParser.y" { jpElementStart(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3632 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3636 "cmDependsJavaParser.cxx" break; case 136: -#line 1220 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1220 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3640,22 +3644,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3644 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3648 "cmDependsJavaParser.cxx" break; case 137: -#line 1229 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1229 "cmDependsJavaParser.y" { jpElementStart(2); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3655 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3659 "cmDependsJavaParser.cxx" break; case 138: -#line 1238 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1238 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3663,11 +3667,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3667 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3671 "cmDependsJavaParser.cxx" break; case 139: -#line 1248 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1248 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -3675,11 +3679,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3679 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3683 "cmDependsJavaParser.cxx" break; case 140: -#line 1258 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1258 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3687,11 +3691,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3691 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3695 "cmDependsJavaParser.cxx" break; case 141: -#line 1267 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1267 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -3699,11 +3703,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3703 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3707 "cmDependsJavaParser.cxx" break; case 142: -#line 1277 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1277 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -3711,22 +3715,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3715 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3719 "cmDependsJavaParser.cxx" break; case 143: -#line 1286 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1286 "cmDependsJavaParser.y" { jpElementStart(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3726 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3730 "cmDependsJavaParser.cxx" break; case 144: -#line 1294 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1294 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3734,11 +3738,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3738 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3742 "cmDependsJavaParser.cxx" break; case 145: -#line 1303 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1303 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -3746,11 +3750,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3750 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3754 "cmDependsJavaParser.cxx" break; case 146: -#line 1313 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1313 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3758,11 +3762,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3762 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3766 "cmDependsJavaParser.cxx" break; case 147: -#line 1322 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1322 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -3770,33 +3774,33 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3774 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3778 "cmDependsJavaParser.cxx" break; case 148: -#line 1332 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1332 "cmDependsJavaParser.y" { jpElementStart(4); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3785 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3789 "cmDependsJavaParser.cxx" break; case 149: -#line 1340 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1340 "cmDependsJavaParser.y" { jpElementStart(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 3796 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3800 "cmDependsJavaParser.cxx" break; case 150: -#line 1348 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1348 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3804,11 +3808,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3808 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3812 "cmDependsJavaParser.cxx" break; case 151: -#line 1358 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1358 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3816,11 +3820,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3820 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3824 "cmDependsJavaParser.cxx" break; case 152: -#line 1367 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1367 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(2); @@ -3828,11 +3832,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3832 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3836 "cmDependsJavaParser.cxx" break; case 153: -#line 1377 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1377 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3840,11 +3844,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3844 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3848 "cmDependsJavaParser.cxx" break; case 154: -#line 1386 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1386 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3852,11 +3856,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3856 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3860 "cmDependsJavaParser.cxx" break; case 155: -#line 1395 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1395 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3864,11 +3868,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3868 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3872 "cmDependsJavaParser.cxx" break; case 156: -#line 1405 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1405 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(2); @@ -3876,11 +3880,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3880 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3884 "cmDependsJavaParser.cxx" break; case 157: -#line 1415 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1415 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(3); @@ -3888,11 +3892,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3892 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3896 "cmDependsJavaParser.cxx" break; case 158: -#line 1424 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1424 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(2); @@ -3900,11 +3904,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3904 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3908 "cmDependsJavaParser.cxx" break; case 159: -#line 1434 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1434 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3912,11 +3916,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3916 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3920 "cmDependsJavaParser.cxx" break; case 160: -#line 1443 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1443 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3924,11 +3928,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3928 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3932 "cmDependsJavaParser.cxx" break; case 161: -#line 1452 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1452 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3936,11 +3940,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3940 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3944 "cmDependsJavaParser.cxx" break; case 162: -#line 1461 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1461 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3948,11 +3952,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3952 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3956 "cmDependsJavaParser.cxx" break; case 163: -#line 1470 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1470 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3960,11 +3964,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3964 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3968 "cmDependsJavaParser.cxx" break; case 164: -#line 1479 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1479 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3972,11 +3976,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3976 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3980 "cmDependsJavaParser.cxx" break; case 165: -#line 1489 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1489 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3984,11 +3988,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 3988 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 3992 "cmDependsJavaParser.cxx" break; case 166: -#line 1498 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1498 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -3996,11 +4000,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4000 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4004 "cmDependsJavaParser.cxx" break; case 167: -#line 1507 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1507 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4008,11 +4012,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4012 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4016 "cmDependsJavaParser.cxx" break; case 168: -#line 1516 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1516 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4020,11 +4024,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4024 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4028 "cmDependsJavaParser.cxx" break; case 169: -#line 1525 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1525 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4032,11 +4036,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4036 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4040 "cmDependsJavaParser.cxx" break; case 170: -#line 1535 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1535 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4044,11 +4048,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4048 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4052 "cmDependsJavaParser.cxx" break; case 171: -#line 1544 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1544 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4056,11 +4060,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4060 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4064 "cmDependsJavaParser.cxx" break; case 172: -#line 1553 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1553 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4068,11 +4072,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4072 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4076 "cmDependsJavaParser.cxx" break; case 173: -#line 1562 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1562 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4080,11 +4084,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4084 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4088 "cmDependsJavaParser.cxx" break; case 174: -#line 1571 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1571 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4092,11 +4096,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4096 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4100 "cmDependsJavaParser.cxx" break; case 175: -#line 1580 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1580 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4104,11 +4108,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4108 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4112 "cmDependsJavaParser.cxx" break; case 176: -#line 1589 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1589 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4116,11 +4120,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4120 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4124 "cmDependsJavaParser.cxx" break; case 177: -#line 1598 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1598 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4128,11 +4132,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4132 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4136 "cmDependsJavaParser.cxx" break; case 178: -#line 1607 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1607 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4140,11 +4144,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4144 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4148 "cmDependsJavaParser.cxx" break; case 179: -#line 1616 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1616 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4152,11 +4156,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4156 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4160 "cmDependsJavaParser.cxx" break; case 180: -#line 1625 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1625 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4164,11 +4168,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4168 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4172 "cmDependsJavaParser.cxx" break; case 181: -#line 1634 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1634 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4176,11 +4180,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4180 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4184 "cmDependsJavaParser.cxx" break; case 182: -#line 1644 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1644 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4188,11 +4192,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4192 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4196 "cmDependsJavaParser.cxx" break; case 183: -#line 1654 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1654 "cmDependsJavaParser.y" { jpElementStart(3); yyGetParser->DeallocateParserType(&((yyvsp[-2].str))); @@ -4201,11 +4205,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4205 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4209 "cmDependsJavaParser.cxx" break; case 184: -#line 1665 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1665 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -4213,11 +4217,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4217 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4221 "cmDependsJavaParser.cxx" break; case 185: -#line 1675 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1675 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -4225,11 +4229,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4229 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4233 "cmDependsJavaParser.cxx" break; case 186: -#line 1685 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1685 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4237,11 +4241,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4241 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4245 "cmDependsJavaParser.cxx" break; case 187: -#line 1694 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1694 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4249,11 +4253,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4253 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4257 "cmDependsJavaParser.cxx" break; case 188: -#line 1703 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1703 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4261,11 +4265,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4265 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4269 "cmDependsJavaParser.cxx" break; case 189: -#line 1712 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1712 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4273,11 +4277,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4277 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4281 "cmDependsJavaParser.cxx" break; case 190: -#line 1721 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1721 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4285,11 +4289,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4289 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4293 "cmDependsJavaParser.cxx" break; case 191: -#line 1730 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1730 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4297,11 +4301,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4301 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4305 "cmDependsJavaParser.cxx" break; case 192: -#line 1739 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1739 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4309,11 +4313,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4313 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4317 "cmDependsJavaParser.cxx" break; case 193: -#line 1749 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1749 "cmDependsJavaParser.y" { jpElementStart(5); jpCheckEmpty(5); @@ -4321,11 +4325,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4325 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4329 "cmDependsJavaParser.cxx" break; case 194: -#line 1759 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1759 "cmDependsJavaParser.y" { jpElementStart(7); jpCheckEmpty(7); @@ -4333,11 +4337,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4337 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4341 "cmDependsJavaParser.cxx" break; case 195: -#line 1769 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1769 "cmDependsJavaParser.y" { jpElementStart(7); jpCheckEmpty(7); @@ -4345,40 +4349,40 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4349 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4353 "cmDependsJavaParser.cxx" break; case 196: -#line 1779 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1779 "cmDependsJavaParser.y" { jpElementStart(5); } -#line 4358 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4362 "cmDependsJavaParser.cxx" break; case 197: -#line 1786 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1786 "cmDependsJavaParser.y" { jpElementStart(4); } -#line 4367 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4371 "cmDependsJavaParser.cxx" break; case 198: -#line 1792 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1792 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 4378 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4382 "cmDependsJavaParser.cxx" break; case 199: -#line 1800 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1800 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4386,22 +4390,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4390 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4394 "cmDependsJavaParser.cxx" break; case 200: -#line 1809 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1809 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 4401 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4405 "cmDependsJavaParser.cxx" break; case 201: -#line 1817 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1817 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -4409,11 +4413,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4413 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4417 "cmDependsJavaParser.cxx" break; case 202: -#line 1827 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1827 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -4421,11 +4425,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4425 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4429 "cmDependsJavaParser.cxx" break; case 203: -#line 1837 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1837 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4433,11 +4437,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4437 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4441 "cmDependsJavaParser.cxx" break; case 204: -#line 1846 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1846 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -4445,11 +4449,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4449 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4453 "cmDependsJavaParser.cxx" break; case 205: -#line 1856 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1856 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -4457,11 +4461,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4461 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4465 "cmDependsJavaParser.cxx" break; case 206: -#line 1865 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1865 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -4469,58 +4473,58 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4473 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4477 "cmDependsJavaParser.cxx" break; case 207: -#line 1875 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1875 "cmDependsJavaParser.y" { jpElementStart(5); } -#line 4482 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4486 "cmDependsJavaParser.cxx" break; case 208: -#line 1882 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1882 "cmDependsJavaParser.y" { jpElementStart(5); } -#line 4491 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4495 "cmDependsJavaParser.cxx" break; case 209: -#line 1889 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1889 "cmDependsJavaParser.y" { jpElementStart(7); } -#line 4500 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4504 "cmDependsJavaParser.cxx" break; case 210: -#line 1897 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1897 "cmDependsJavaParser.y" { jpElementStart(9); } -#line 4509 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4513 "cmDependsJavaParser.cxx" break; case 211: -#line 1903 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1903 "cmDependsJavaParser.y" { jpElementStart(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 4520 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4524 "cmDependsJavaParser.cxx" break; case 212: -#line 1911 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1911 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4528,22 +4532,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4532 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4536 "cmDependsJavaParser.cxx" break; case 213: -#line 1920 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1920 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 4543 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4547 "cmDependsJavaParser.cxx" break; case 214: -#line 1928 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1928 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4551,33 +4555,33 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4555 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4559 "cmDependsJavaParser.cxx" break; case 215: -#line 1939 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1939 "cmDependsJavaParser.y" { jpElementStart(9); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 4566 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4570 "cmDependsJavaParser.cxx" break; case 216: -#line 1947 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1947 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 4577 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4581 "cmDependsJavaParser.cxx" break; case 217: -#line 1955 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1955 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4585,11 +4589,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4589 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4593 "cmDependsJavaParser.cxx" break; case 218: -#line 1965 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1965 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4597,11 +4601,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4601 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4605 "cmDependsJavaParser.cxx" break; case 219: -#line 1974 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1974 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4609,11 +4613,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4613 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4617 "cmDependsJavaParser.cxx" break; case 220: -#line 1984 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1984 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4621,11 +4625,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4625 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4629 "cmDependsJavaParser.cxx" break; case 221: -#line 1994 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 1994 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4633,11 +4637,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4637 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4641 "cmDependsJavaParser.cxx" break; case 222: -#line 2003 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2003 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -4645,11 +4649,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4649 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4653 "cmDependsJavaParser.cxx" break; case 223: -#line 2013 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2013 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -4657,11 +4661,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4661 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4665 "cmDependsJavaParser.cxx" break; case 224: -#line 2022 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2022 "cmDependsJavaParser.y" { jpElementStart(5); jpCheckEmpty(5); @@ -4669,11 +4673,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4673 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4677 "cmDependsJavaParser.cxx" break; case 225: -#line 2032 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2032 "cmDependsJavaParser.y" { jpElementStart(3); yyGetParser->DeallocateParserType(&((yyvsp[-1].str))); @@ -4682,31 +4686,31 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4686 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4690 "cmDependsJavaParser.cxx" break; case 226: -#line 2042 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2042 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 4697 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4701 "cmDependsJavaParser.cxx" break; case 227: -#line 2050 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2050 "cmDependsJavaParser.y" { jpElementStart(1); } -#line 4706 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4710 "cmDependsJavaParser.cxx" break; case 228: -#line 2057 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2057 "cmDependsJavaParser.y" { jpElementStart(3); yyGetParser->DeallocateParserType(&((yyvsp[-1].str))); @@ -4715,11 +4719,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4719 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4723 "cmDependsJavaParser.cxx" break; case 229: -#line 2068 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2068 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -4727,11 +4731,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4731 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4735 "cmDependsJavaParser.cxx" break; case 230: -#line 2078 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2078 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -4739,11 +4743,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4743 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4747 "cmDependsJavaParser.cxx" break; case 231: -#line 2088 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2088 "cmDependsJavaParser.y" { jpElementStart(5); jpCheckEmpty(5); @@ -4751,11 +4755,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4755 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4759 "cmDependsJavaParser.cxx" break; case 232: -#line 2098 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2098 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -4763,11 +4767,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4767 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4771 "cmDependsJavaParser.cxx" break; case 233: -#line 2107 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2107 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -4775,22 +4779,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4779 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4783 "cmDependsJavaParser.cxx" break; case 234: -#line 2116 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2116 "cmDependsJavaParser.y" { jpElementStart(1); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 4790 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4794 "cmDependsJavaParser.cxx" break; case 235: -#line 2124 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2124 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4798,11 +4802,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4802 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4806 "cmDependsJavaParser.cxx" break; case 236: -#line 2134 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2134 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4810,11 +4814,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4814 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4818 "cmDependsJavaParser.cxx" break; case 237: -#line 2143 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2143 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -4822,20 +4826,20 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4826 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4830 "cmDependsJavaParser.cxx" break; case 238: -#line 2153 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2153 "cmDependsJavaParser.y" { jpElementStart(5); } -#line 4835 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4839 "cmDependsJavaParser.cxx" break; case 239: -#line 2160 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2160 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -4843,11 +4847,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4847 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4851 "cmDependsJavaParser.cxx" break; case 240: -#line 2170 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2170 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4855,11 +4859,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4859 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4863 "cmDependsJavaParser.cxx" break; case 241: -#line 2179 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2179 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4867,11 +4871,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4871 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4875 "cmDependsJavaParser.cxx" break; case 242: -#line 2189 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2189 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4879,20 +4883,20 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4883 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4887 "cmDependsJavaParser.cxx" break; case 243: -#line 2198 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2198 "cmDependsJavaParser.y" { jpElementStart(1); } -#line 4892 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4896 "cmDependsJavaParser.cxx" break; case 244: -#line 2204 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2204 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -4900,11 +4904,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4904 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4908 "cmDependsJavaParser.cxx" break; case 245: -#line 2213 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2213 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4912,11 +4916,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4916 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4920 "cmDependsJavaParser.cxx" break; case 246: -#line 2222 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2222 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4924,11 +4928,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4928 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4932 "cmDependsJavaParser.cxx" break; case 247: -#line 2231 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2231 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4936,11 +4940,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4940 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4944 "cmDependsJavaParser.cxx" break; case 248: -#line 2240 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2240 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4948,11 +4952,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4952 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4956 "cmDependsJavaParser.cxx" break; case 249: -#line 2250 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2250 "cmDependsJavaParser.y" { jpElementStart(6); jpCheckEmpty(6); @@ -4960,22 +4964,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4964 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4968 "cmDependsJavaParser.cxx" break; case 250: -#line 2259 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2259 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 4975 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4979 "cmDependsJavaParser.cxx" break; case 251: -#line 2267 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2267 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -4983,22 +4987,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 4987 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 4991 "cmDependsJavaParser.cxx" break; case 252: -#line 2276 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2276 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 4998 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5002 "cmDependsJavaParser.cxx" break; case 253: -#line 2284 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2284 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5006,11 +5010,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5010 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5014 "cmDependsJavaParser.cxx" break; case 254: -#line 2294 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2294 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5018,11 +5022,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5022 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5026 "cmDependsJavaParser.cxx" break; case 255: -#line 2303 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2303 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5030,11 +5034,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5034 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5038 "cmDependsJavaParser.cxx" break; case 256: -#line 2313 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2313 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -5042,11 +5046,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5046 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5050 "cmDependsJavaParser.cxx" break; case 257: -#line 2322 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2322 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -5054,11 +5058,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5058 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5062 "cmDependsJavaParser.cxx" break; case 258: -#line 2331 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2331 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -5066,11 +5070,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5070 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5074 "cmDependsJavaParser.cxx" break; case 259: -#line 2340 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2340 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -5078,22 +5082,22 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5082 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5086 "cmDependsJavaParser.cxx" break; case 260: -#line 2349 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2349 "cmDependsJavaParser.y" { jpElementStart(0); (yyval.str) = 0; yyGetParser->SetCurrentCombine(""); } -#line 5093 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5097 "cmDependsJavaParser.cxx" break; case 261: -#line 2357 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2357 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5101,11 +5105,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5105 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5109 "cmDependsJavaParser.cxx" break; case 262: -#line 2367 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2367 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5113,11 +5117,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5117 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5121 "cmDependsJavaParser.cxx" break; case 263: -#line 2376 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2376 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -5125,11 +5129,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5129 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5133 "cmDependsJavaParser.cxx" break; case 264: -#line 2386 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2386 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5137,29 +5141,29 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5141 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5145 "cmDependsJavaParser.cxx" break; case 265: -#line 2396 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2396 "cmDependsJavaParser.y" { jpElementStart(2); } -#line 5150 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5154 "cmDependsJavaParser.cxx" break; case 266: -#line 2402 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2402 "cmDependsJavaParser.y" { jpElementStart(3); } -#line 5159 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5163 "cmDependsJavaParser.cxx" break; case 267: -#line 2409 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2409 "cmDependsJavaParser.y" { jpElementStart(3); yyGetParser->DeallocateParserType(&((yyvsp[0].str))); @@ -5168,11 +5172,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5172 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5176 "cmDependsJavaParser.cxx" break; case 268: -#line 2419 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2419 "cmDependsJavaParser.y" { jpElementStart(3); yyGetParser->DeallocateParserType(&((yyvsp[0].str))); @@ -5181,11 +5185,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5185 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5189 "cmDependsJavaParser.cxx" break; case 269: -#line 2429 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2429 "cmDependsJavaParser.y" { jpElementStart(3); yyGetParser->DeallocateParserType(&((yyvsp[0].str))); @@ -5194,11 +5198,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5198 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5202 "cmDependsJavaParser.cxx" break; case 270: -#line 2439 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2439 "cmDependsJavaParser.y" { jpElementStart(3); yyGetParser->DeallocateParserType(&((yyvsp[0].str))); @@ -5207,11 +5211,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5211 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5215 "cmDependsJavaParser.cxx" break; case 271: -#line 2450 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2450 "cmDependsJavaParser.y" { jpElementStart(4); yyGetParser->DeallocateParserType(&((yyvsp[-3].str))); @@ -5220,11 +5224,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5224 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5228 "cmDependsJavaParser.cxx" break; case 272: -#line 2460 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2460 "cmDependsJavaParser.y" { jpElementStart(6); yyGetParser->DeallocateParserType(&((yyvsp[-5].str))); @@ -5234,11 +5238,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5238 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5242 "cmDependsJavaParser.cxx" break; case 273: -#line 2471 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2471 "cmDependsJavaParser.y" { jpElementStart(6); yyGetParser->DeallocateParserType(&((yyvsp[-3].str))); @@ -5247,11 +5251,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5251 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5255 "cmDependsJavaParser.cxx" break; case 274: -#line 2481 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2481 "cmDependsJavaParser.y" { jpElementStart(6); yyGetParser->DeallocateParserType(&((yyvsp[-3].str))); @@ -5260,11 +5264,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5264 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5268 "cmDependsJavaParser.cxx" break; case 275: -#line 2492 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2492 "cmDependsJavaParser.y" { jpElementStart(4); yyGetParser->DeallocateParserType(&((yyvsp[-3].str))); @@ -5273,11 +5277,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5277 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5281 "cmDependsJavaParser.cxx" break; case 276: -#line 2502 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2502 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -5285,11 +5289,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5289 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5293 "cmDependsJavaParser.cxx" break; case 277: -#line 2512 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2512 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5297,11 +5301,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5301 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5305 "cmDependsJavaParser.cxx" break; case 278: -#line 2521 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2521 "cmDependsJavaParser.y" { jpElementStart(1); yyGetParser->DeallocateParserType(&((yyvsp[0].str))); @@ -5309,11 +5313,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5313 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5317 "cmDependsJavaParser.cxx" break; case 279: -#line 2530 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2530 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5321,11 +5325,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5325 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5329 "cmDependsJavaParser.cxx" break; case 280: -#line 2539 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2539 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5333,11 +5337,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5337 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5341 "cmDependsJavaParser.cxx" break; case 281: -#line 2548 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2548 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5345,11 +5349,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5349 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5353 "cmDependsJavaParser.cxx" break; case 282: -#line 2558 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2558 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -5357,11 +5361,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5361 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5365 "cmDependsJavaParser.cxx" break; case 283: -#line 2568 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2568 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -5369,11 +5373,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5373 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5377 "cmDependsJavaParser.cxx" break; case 284: -#line 2578 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2578 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5381,11 +5385,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5385 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5389 "cmDependsJavaParser.cxx" break; case 285: -#line 2587 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2587 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5393,11 +5397,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5397 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5401 "cmDependsJavaParser.cxx" break; case 286: -#line 2596 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2596 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -5405,11 +5409,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5409 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5413 "cmDependsJavaParser.cxx" break; case 287: -#line 2605 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2605 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -5417,11 +5421,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5421 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5425 "cmDependsJavaParser.cxx" break; case 288: -#line 2614 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2614 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5429,11 +5433,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5433 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5437 "cmDependsJavaParser.cxx" break; case 289: -#line 2624 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2624 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -5441,11 +5445,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5445 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5449 "cmDependsJavaParser.cxx" break; case 290: -#line 2634 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2634 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -5453,11 +5457,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5457 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5461 "cmDependsJavaParser.cxx" break; case 291: -#line 2644 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2644 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5465,11 +5469,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5469 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5473 "cmDependsJavaParser.cxx" break; case 292: -#line 2653 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2653 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -5477,11 +5481,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5481 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5485 "cmDependsJavaParser.cxx" break; case 293: -#line 2662 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2662 "cmDependsJavaParser.y" { jpElementStart(2); jpCheckEmpty(2); @@ -5489,11 +5493,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5493 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5497 "cmDependsJavaParser.cxx" break; case 294: -#line 2671 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2671 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5501,11 +5505,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5505 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5509 "cmDependsJavaParser.cxx" break; case 295: -#line 2681 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2681 "cmDependsJavaParser.y" { jpElementStart(5); jpCheckEmpty(5); @@ -5513,11 +5517,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5517 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5521 "cmDependsJavaParser.cxx" break; case 296: -#line 2690 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2690 "cmDependsJavaParser.y" { jpElementStart(4); jpCheckEmpty(4); @@ -5525,20 +5529,20 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5529 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5533 "cmDependsJavaParser.cxx" break; case 297: -#line 2699 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2699 "cmDependsJavaParser.y" { jpElementStart(5); } -#line 5538 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5542 "cmDependsJavaParser.cxx" break; case 298: -#line 2706 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2706 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5546,11 +5550,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5550 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5554 "cmDependsJavaParser.cxx" break; case 299: -#line 2715 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2715 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5558,11 +5562,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5562 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5566 "cmDependsJavaParser.cxx" break; case 300: -#line 2724 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2724 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5570,11 +5574,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5574 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5578 "cmDependsJavaParser.cxx" break; case 301: -#line 2733 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2733 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5582,11 +5586,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5586 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5590 "cmDependsJavaParser.cxx" break; case 302: -#line 2743 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2743 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5594,11 +5598,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5598 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5602 "cmDependsJavaParser.cxx" break; case 303: -#line 2752 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2752 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5606,11 +5610,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5610 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5614 "cmDependsJavaParser.cxx" break; case 304: -#line 2761 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2761 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5618,11 +5622,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5622 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5626 "cmDependsJavaParser.cxx" break; case 305: -#line 2771 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2771 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5630,11 +5634,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5634 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5638 "cmDependsJavaParser.cxx" break; case 306: -#line 2780 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2780 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5642,11 +5646,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5646 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5650 "cmDependsJavaParser.cxx" break; case 307: -#line 2789 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2789 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5654,11 +5658,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5658 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5662 "cmDependsJavaParser.cxx" break; case 308: -#line 2798 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2798 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5666,11 +5670,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5670 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5674 "cmDependsJavaParser.cxx" break; case 309: -#line 2808 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2808 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5678,11 +5682,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5682 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5686 "cmDependsJavaParser.cxx" break; case 310: -#line 2817 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2817 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5690,11 +5694,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5694 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5698 "cmDependsJavaParser.cxx" break; case 311: -#line 2826 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2826 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5702,11 +5706,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5706 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5710 "cmDependsJavaParser.cxx" break; case 312: -#line 2835 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2835 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5714,11 +5718,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5718 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5722 "cmDependsJavaParser.cxx" break; case 313: -#line 2844 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2844 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5726,11 +5730,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5730 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5734 "cmDependsJavaParser.cxx" break; case 314: -#line 2853 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2853 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5738,11 +5742,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5742 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5746 "cmDependsJavaParser.cxx" break; case 315: -#line 2863 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2863 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5750,11 +5754,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5754 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5758 "cmDependsJavaParser.cxx" break; case 316: -#line 2872 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2872 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5762,11 +5766,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5766 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5770 "cmDependsJavaParser.cxx" break; case 317: -#line 2881 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2881 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5774,11 +5778,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5778 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5782 "cmDependsJavaParser.cxx" break; case 318: -#line 2891 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2891 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5786,11 +5790,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5790 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5794 "cmDependsJavaParser.cxx" break; case 319: -#line 2900 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2900 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5798,11 +5802,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5802 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5806 "cmDependsJavaParser.cxx" break; case 320: -#line 2910 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2910 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5810,11 +5814,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5814 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5818 "cmDependsJavaParser.cxx" break; case 321: -#line 2919 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2919 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5822,11 +5826,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5826 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5830 "cmDependsJavaParser.cxx" break; case 322: -#line 2929 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2929 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5834,11 +5838,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5838 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5842 "cmDependsJavaParser.cxx" break; case 323: -#line 2938 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2938 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5846,11 +5850,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5850 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5854 "cmDependsJavaParser.cxx" break; case 324: -#line 2948 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2948 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5858,11 +5862,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5862 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5866 "cmDependsJavaParser.cxx" break; case 325: -#line 2957 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2957 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5870,11 +5874,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5874 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5878 "cmDependsJavaParser.cxx" break; case 326: -#line 2967 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2967 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5882,11 +5886,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5886 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5890 "cmDependsJavaParser.cxx" break; case 327: -#line 2976 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2976 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5894,11 +5898,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5898 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5902 "cmDependsJavaParser.cxx" break; case 328: -#line 2986 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2986 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5906,11 +5910,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5910 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5914 "cmDependsJavaParser.cxx" break; case 329: -#line 2995 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 2995 "cmDependsJavaParser.y" { jpElementStart(5); jpCheckEmpty(5); @@ -5918,11 +5922,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5922 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5926 "cmDependsJavaParser.cxx" break; case 330: -#line 3005 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3005 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5930,11 +5934,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5934 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5938 "cmDependsJavaParser.cxx" break; case 331: -#line 3014 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3014 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5942,11 +5946,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5946 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5950 "cmDependsJavaParser.cxx" break; case 332: -#line 3024 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3024 "cmDependsJavaParser.y" { jpElementStart(3); jpCheckEmpty(3); @@ -5954,11 +5958,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5958 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5962 "cmDependsJavaParser.cxx" break; case 333: -#line 3034 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3034 "cmDependsJavaParser.y" { jpElementStart(1); yyGetParser->DeallocateParserType(&((yyvsp[0].str))); @@ -5967,11 +5971,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5971 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5975 "cmDependsJavaParser.cxx" break; case 334: -#line 3044 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3044 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5979,11 +5983,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5983 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5987 "cmDependsJavaParser.cxx" break; case 335: -#line 3053 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3053 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -5991,11 +5995,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 5995 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 5999 "cmDependsJavaParser.cxx" break; case 336: -#line 3063 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3063 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6003,11 +6007,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6007 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6011 "cmDependsJavaParser.cxx" break; case 337: -#line 3072 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3072 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6015,11 +6019,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6019 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6023 "cmDependsJavaParser.cxx" break; case 338: -#line 3081 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3081 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6027,11 +6031,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6031 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6035 "cmDependsJavaParser.cxx" break; case 339: -#line 3090 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3090 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6039,11 +6043,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6043 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6047 "cmDependsJavaParser.cxx" break; case 340: -#line 3099 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3099 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6051,11 +6055,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6055 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6059 "cmDependsJavaParser.cxx" break; case 341: -#line 3108 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3108 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6063,11 +6067,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6067 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6071 "cmDependsJavaParser.cxx" break; case 342: -#line 3117 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3117 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6075,11 +6079,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6079 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6083 "cmDependsJavaParser.cxx" break; case 343: -#line 3126 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3126 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6087,11 +6091,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6091 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6095 "cmDependsJavaParser.cxx" break; case 344: -#line 3135 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3135 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6099,11 +6103,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6103 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6107 "cmDependsJavaParser.cxx" break; case 345: -#line 3144 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3144 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6111,11 +6115,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6115 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6119 "cmDependsJavaParser.cxx" break; case 346: -#line 3153 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3153 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6123,11 +6127,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6127 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6131 "cmDependsJavaParser.cxx" break; case 347: -#line 3162 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3162 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6135,11 +6139,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6139 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6143 "cmDependsJavaParser.cxx" break; case 348: -#line 3172 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3172 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6147,11 +6151,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6151 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6155 "cmDependsJavaParser.cxx" break; case 349: -#line 3182 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3182 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6159,11 +6163,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6163 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6167 "cmDependsJavaParser.cxx" break; case 350: -#line 3192 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3192 "cmDependsJavaParser.y" { jpElementStart(1); jpCheckEmpty(1); @@ -6171,11 +6175,11 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6175 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6179 "cmDependsJavaParser.cxx" break; case 351: -#line 3201 "cmDependsJavaParser.y" /* yacc.c:1652 */ +#line 3201 "cmDependsJavaParser.y" { jpElementStart(3); jpStoreClass((yyvsp[-2].str)); @@ -6184,11 +6188,12 @@ yyreduce: yyGetParser->SetCurrentCombine(""); } -#line 6188 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6192 "cmDependsJavaParser.cxx" break; -#line 6192 "cmDependsJavaParser.cxx" /* yacc.c:1652 */ +#line 6196 "cmDependsJavaParser.cxx" + default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -6421,7 +6426,7 @@ yyreturn: #endif return yyresult; } -#line 3210 "cmDependsJavaParser.y" /* yacc.c:1918 */ +#line 3210 "cmDependsJavaParser.y" /* End of grammar */ diff --git a/Source/LexerParser/cmDependsJavaParserTokens.h b/Source/LexerParser/cmDependsJavaParserTokens.h index 6bbc084..e0dfa01 100644 --- a/Source/LexerParser/cmDependsJavaParserTokens.h +++ b/Source/LexerParser/cmDependsJavaParserTokens.h @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.3.2. */ +/* A Bison parser, made by GNU Bison 3.4.2. */ /* Bison interface for Yacc-like parsers in C diff --git a/Source/LexerParser/cmExprParser.cxx b/Source/LexerParser/cmExprParser.cxx index 8416e72..562b35b 100644 --- a/Source/LexerParser/cmExprParser.cxx +++ b/Source/LexerParser/cmExprParser.cxx @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.3.2. */ +/* A Bison parser, made by GNU Bison 3.4.2. */ /* Bison implementation for Yacc-like parsers in C @@ -48,7 +48,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.3.2" +#define YYBISON_VERSION "3.4.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -72,7 +72,7 @@ /* First part of user prologue. */ -#line 1 "cmExprParser.y" /* yacc.c:337 */ +#line 1 "cmExprParser.y" /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ @@ -116,7 +116,8 @@ static void cmExpr_yyerror(yyscan_t yyscanner, const char* message); # pragma GCC diagnostic ignored "-Wconversion" #endif -#line 120 "cmExprParser.cxx" /* yacc.c:337 */ +#line 120 "cmExprParser.cxx" + # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus @@ -137,8 +138,8 @@ static void cmExpr_yyerror(yyscan_t yyscanner, const char* message); # define YYERROR_VERBOSE 1 #endif -/* In a future release of Bison, this section will be replaced - by #include "cmExprParserTokens.h". */ +/* Use api.header.include to #include this header + instead of duplicating it here. */ #ifndef YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED # define YY_CMEXPR_YY_CMEXPRPARSERTOKENS_H_INCLUDED /* Debug traces. */ @@ -296,6 +297,8 @@ typedef short yytype_int16; #endif +#define YY_ASSERT(E) ((void) (0 && (E))) + #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ @@ -688,7 +691,9 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy if (yytype < YYNTOKENS) YYPRINT (yyo, yytoknum[yytype], *yyvaluep); # endif + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -1126,6 +1131,8 @@ yynewstate: | yynewstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); *yyssp = (yytype_int16) yystate; if (yyss + yystacksize - 1 <= yyssp) @@ -1188,8 +1195,6 @@ yysetstate: } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - if (yystate == YYFINAL) YYACCEPT; @@ -1257,7 +1262,6 @@ yybackup: YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END - goto yynewstate; @@ -1292,195 +1296,196 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 2: -#line 77 "cmExprParser.y" /* yacc.c:1652 */ + case 2: +#line 77 "cmExprParser.y" { cmExpr_yyget_extra(yyscanner)->SetResult((yyvsp[0].Number)); } -#line 1301 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1305 "cmExprParser.cxx" break; case 3: -#line 82 "cmExprParser.y" /* yacc.c:1652 */ +#line 82 "cmExprParser.y" { (yyval.Number) = (yyvsp[0].Number); } -#line 1309 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1313 "cmExprParser.cxx" break; case 4: -#line 85 "cmExprParser.y" /* yacc.c:1652 */ +#line 85 "cmExprParser.y" { (yyval.Number) = (yyvsp[-2].Number) | (yyvsp[0].Number); } -#line 1317 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1321 "cmExprParser.cxx" break; case 5: -#line 90 "cmExprParser.y" /* yacc.c:1652 */ +#line 90 "cmExprParser.y" { (yyval.Number) = (yyvsp[0].Number); } -#line 1325 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1329 "cmExprParser.cxx" break; case 6: -#line 93 "cmExprParser.y" /* yacc.c:1652 */ +#line 93 "cmExprParser.y" { (yyval.Number) = (yyvsp[-2].Number) ^ (yyvsp[0].Number); } -#line 1333 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1337 "cmExprParser.cxx" break; case 7: -#line 98 "cmExprParser.y" /* yacc.c:1652 */ +#line 98 "cmExprParser.y" { (yyval.Number) = (yyvsp[0].Number); } -#line 1341 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1345 "cmExprParser.cxx" break; case 8: -#line 101 "cmExprParser.y" /* yacc.c:1652 */ +#line 101 "cmExprParser.y" { (yyval.Number) = (yyvsp[-2].Number) & (yyvsp[0].Number); } -#line 1349 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1353 "cmExprParser.cxx" break; case 9: -#line 106 "cmExprParser.y" /* yacc.c:1652 */ +#line 106 "cmExprParser.y" { (yyval.Number) = (yyvsp[0].Number); } -#line 1357 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1361 "cmExprParser.cxx" break; case 10: -#line 109 "cmExprParser.y" /* yacc.c:1652 */ +#line 109 "cmExprParser.y" { (yyval.Number) = (yyvsp[-2].Number) << (yyvsp[0].Number); } -#line 1365 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1369 "cmExprParser.cxx" break; case 11: -#line 112 "cmExprParser.y" /* yacc.c:1652 */ +#line 112 "cmExprParser.y" { (yyval.Number) = (yyvsp[-2].Number) >> (yyvsp[0].Number); } -#line 1373 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1377 "cmExprParser.cxx" break; case 12: -#line 117 "cmExprParser.y" /* yacc.c:1652 */ +#line 117 "cmExprParser.y" { (yyval.Number) = (yyvsp[0].Number); } -#line 1381 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1385 "cmExprParser.cxx" break; case 13: -#line 120 "cmExprParser.y" /* yacc.c:1652 */ +#line 120 "cmExprParser.y" { (yyval.Number) = (yyvsp[-2].Number) + (yyvsp[0].Number); } -#line 1389 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1393 "cmExprParser.cxx" break; case 14: -#line 123 "cmExprParser.y" /* yacc.c:1652 */ +#line 123 "cmExprParser.y" { (yyval.Number) = (yyvsp[-2].Number) - (yyvsp[0].Number); } -#line 1397 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1401 "cmExprParser.cxx" break; case 15: -#line 128 "cmExprParser.y" /* yacc.c:1652 */ +#line 128 "cmExprParser.y" { (yyval.Number) = (yyvsp[0].Number); } -#line 1405 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1409 "cmExprParser.cxx" break; case 16: -#line 131 "cmExprParser.y" /* yacc.c:1652 */ +#line 131 "cmExprParser.y" { (yyval.Number) = (yyvsp[-2].Number) * (yyvsp[0].Number); } -#line 1413 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1417 "cmExprParser.cxx" break; case 17: -#line 134 "cmExprParser.y" /* yacc.c:1652 */ +#line 134 "cmExprParser.y" { if (yyvsp[0].Number == 0) { throw std::overflow_error("divide by zero"); } (yyval.Number) = (yyvsp[-2].Number) / (yyvsp[0].Number); } -#line 1424 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1428 "cmExprParser.cxx" break; case 18: -#line 140 "cmExprParser.y" /* yacc.c:1652 */ +#line 140 "cmExprParser.y" { (yyval.Number) = (yyvsp[-2].Number) % (yyvsp[0].Number); } -#line 1432 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1436 "cmExprParser.cxx" break; case 19: -#line 145 "cmExprParser.y" /* yacc.c:1652 */ +#line 145 "cmExprParser.y" { (yyval.Number) = (yyvsp[0].Number); } -#line 1440 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1444 "cmExprParser.cxx" break; case 20: -#line 148 "cmExprParser.y" /* yacc.c:1652 */ +#line 148 "cmExprParser.y" { (yyval.Number) = + (yyvsp[0].Number); } -#line 1448 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1452 "cmExprParser.cxx" break; case 21: -#line 151 "cmExprParser.y" /* yacc.c:1652 */ +#line 151 "cmExprParser.y" { (yyval.Number) = - (yyvsp[0].Number); } -#line 1456 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1460 "cmExprParser.cxx" break; case 22: -#line 154 "cmExprParser.y" /* yacc.c:1652 */ +#line 154 "cmExprParser.y" { (yyval.Number) = ~ (yyvsp[0].Number); } -#line 1464 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1468 "cmExprParser.cxx" break; case 23: -#line 159 "cmExprParser.y" /* yacc.c:1652 */ +#line 159 "cmExprParser.y" { (yyval.Number) = (yyvsp[0].Number); } -#line 1472 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1476 "cmExprParser.cxx" break; case 24: -#line 162 "cmExprParser.y" /* yacc.c:1652 */ +#line 162 "cmExprParser.y" { (yyval.Number) = (yyvsp[-1].Number); } -#line 1480 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1484 "cmExprParser.cxx" break; -#line 1484 "cmExprParser.cxx" /* yacc.c:1652 */ +#line 1488 "cmExprParser.cxx" + default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1713,7 +1718,7 @@ yyreturn: #endif return yyresult; } -#line 167 "cmExprParser.y" /* yacc.c:1918 */ +#line 167 "cmExprParser.y" /* End of grammar */ diff --git a/Source/LexerParser/cmExprParserTokens.h b/Source/LexerParser/cmExprParserTokens.h index 5ffd7c5..e30a832 100644 --- a/Source/LexerParser/cmExprParserTokens.h +++ b/Source/LexerParser/cmExprParserTokens.h @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.3.2. */ +/* A Bison parser, made by GNU Bison 3.4.2. */ /* Bison interface for Yacc-like parsers in C diff --git a/Source/LexerParser/cmFortranParser.cxx b/Source/LexerParser/cmFortranParser.cxx index 2ca7927..2494aad 100644 --- a/Source/LexerParser/cmFortranParser.cxx +++ b/Source/LexerParser/cmFortranParser.cxx @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.3.2. */ +/* A Bison parser, made by GNU Bison 3.4.2. */ /* Bison implementation for Yacc-like parsers in C @@ -48,7 +48,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.3.2" +#define YYBISON_VERSION "3.4.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -72,7 +72,7 @@ /* First part of user prologue. */ -#line 1 "cmFortranParser.y" /* yacc.c:337 */ +#line 1 "cmFortranParser.y" /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ @@ -135,7 +135,8 @@ static void cmFortran_yyerror(yyscan_t yyscanner, const char* message) # pragma GCC diagnostic ignored "-Wconversion" #endif -#line 139 "cmFortranParser.cxx" /* yacc.c:337 */ +#line 139 "cmFortranParser.cxx" + # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus @@ -156,8 +157,8 @@ static void cmFortran_yyerror(yyscan_t yyscanner, const char* message) # define YYERROR_VERBOSE 1 #endif -/* In a future release of Bison, this section will be replaced - by #include "cmFortranParserTokens.h". */ +/* Use api.header.include to #include this header + instead of duplicating it here. */ #ifndef YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED # define YY_CMFORTRAN_YY_CMFORTRANPARSERTOKENS_H_INCLUDED /* Debug traces. */ @@ -255,16 +256,15 @@ extern int cmFortran_yydebug; /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - union YYSTYPE { -#line 73 "cmFortranParser.y" /* yacc.c:352 */ +#line 73 "cmFortranParser.y" char* string; -#line 266 "cmFortranParser.cxx" /* yacc.c:352 */ -}; +#line 266 "cmFortranParser.cxx" +}; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 @@ -378,6 +378,8 @@ typedef short yytype_int16; #endif +#define YY_ASSERT(E) ((void) (0 && (E))) + #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ @@ -509,16 +511,16 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 593 +#define YYLAST 594 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 41 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 14 /* YYNRULES -- Number of rules. */ -#define YYNRULES 63 +#define YYNRULES 64 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 126 +#define YYNSTATES 127 #define YYUNDEFTOK 2 #define YYMAXUTOK 295 @@ -574,7 +576,7 @@ static const yytype_uint8 yyrline[] = 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 228, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, - 243, 244, 245, 246 + 243, 244, 245, 246, 247 }; #endif @@ -626,16 +628,16 @@ static const yytype_int16 yypact[] = -39, 21, -39, 1, -39, -20, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -24, -18, 20, -8, - -3, 39, -39, 15, 16, 18, 19, 33, -39, -39, + -3, 40, -39, 15, 16, 17, 19, 34, -39, -39, -39, -39, -39, -39, 59, -39, -39, -39, -39, -39, - 35, 36, 37, -39, -39, -39, -39, -39, -39, 76, - 114, 129, 167, 182, -39, -39, -39, -39, -39, -39, + 36, 37, 38, -39, -39, -39, -39, -39, -39, 77, + 115, 130, 168, 183, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, 220, 235, 273, 288, -21, 26, -39, 326, - 341, 379, 394, 432, 447, -39, -39, -39, -39, -39, - -39, -39, -39, -39, 38, 40, 41, 485, -39, -39, - -39, -39, -39, -39, 45, -39, -39, -39, 43, 500, - 538, -39, -39, -39, 553, -39 + -39, -39, -39, 221, 236, 274, 289, -21, 26, -39, + 327, 342, 380, 395, 433, 448, -39, -39, -39, -39, + -39, -39, -39, -39, -39, 39, 41, 42, 486, -39, + -39, -39, -39, -39, -39, 18, -39, -39, -39, 43, + 501, 539, -39, -39, -39, 554, -39 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -649,13 +651,13 @@ static const yytype_uint8 yydefact[] = 0, 0, 3, 0, 0, 0, 0, 0, 46, 46, 46, 46, 26, 46, 0, 46, 46, 4, 46, 46, 0, 0, 0, 46, 46, 46, 46, 46, 46, 0, - 0, 0, 0, 0, 15, 57, 56, 62, 58, 59, - 60, 61, 63, 55, 48, 49, 50, 51, 52, 53, - 54, 47, 0, 0, 0, 0, 0, 0, 46, 0, - 0, 0, 0, 0, 0, 21, 22, 23, 24, 14, - 10, 13, 9, 6, 0, 0, 0, 0, 5, 16, - 17, 18, 19, 20, 0, 46, 46, 11, 0, 0, - 0, 46, 7, 12, 0, 8 + 0, 0, 0, 0, 15, 57, 56, 64, 62, 58, + 59, 60, 61, 63, 55, 48, 49, 50, 51, 52, + 53, 54, 47, 0, 0, 0, 0, 0, 0, 46, + 0, 0, 0, 0, 0, 0, 21, 22, 23, 24, + 14, 10, 13, 9, 6, 0, 0, 0, 0, 5, + 16, 17, 18, 19, 20, 0, 46, 46, 11, 0, + 0, 0, 46, 7, 12, 0, 8 }; /* YYPGOTO[NTERM-NUM]. */ @@ -669,7 +671,7 @@ static const yytype_int8 yypgoto[] = static const yytype_int8 yydefgoto[] = { -1, 1, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 44, 81 + 40, 41, 44, 82 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -677,66 +679,66 @@ static const yytype_int8 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint8 yytable[] = { - 59, 60, 61, 62, 42, 63, 104, 82, 83, 105, - 84, 85, 43, 45, 46, 89, 90, 91, 92, 93, - 94, 2, 3, 47, 4, 49, 50, 5, 6, 7, + 59, 60, 61, 62, 42, 63, 105, 83, 84, 106, + 85, 86, 43, 45, 46, 90, 91, 92, 93, 94, + 95, 2, 3, 47, 4, 49, 50, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 54, 0, 55, - 107, 56, 57, 48, 106, 25, 26, 27, 28, 29, - 30, 31, 64, 65, 66, 51, 58, 52, 86, 87, - 88, 114, 53, 115, 116, 118, 121, 119, 120, 95, - 65, 66, 0, 124, 0, 67, 68, 69, 70, 71, - 72, 73, 74, 0, 75, 76, 77, 78, 79, 80, - 0, 0, 67, 68, 69, 70, 71, 72, 73, 74, - 0, 75, 76, 77, 78, 79, 80, 96, 65, 66, + 18, 19, 20, 21, 22, 23, 24, 54, 119, 55, + 56, 108, 57, 48, 107, 25, 26, 27, 28, 29, + 30, 31, 64, 65, 66, 67, 51, 58, 52, 87, + 88, 89, 115, 53, 116, 117, 122, 0, 120, 121, + 96, 65, 66, 67, 125, 68, 69, 70, 71, 72, + 73, 74, 75, 0, 76, 77, 78, 79, 80, 81, + 0, 0, 0, 68, 69, 70, 71, 72, 73, 74, + 75, 0, 76, 77, 78, 79, 80, 81, 97, 65, + 66, 67, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 98, 65, 66, 67, 0, 0, 0, + 0, 68, 69, 70, 71, 72, 73, 74, 75, 0, + 76, 77, 78, 79, 80, 81, 68, 69, 70, 71, + 72, 73, 74, 75, 0, 76, 77, 78, 79, 80, + 81, 99, 65, 66, 67, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 100, 65, 66, 67, + 0, 0, 0, 0, 68, 69, 70, 71, 72, 73, + 74, 75, 0, 76, 77, 78, 79, 80, 81, 68, + 69, 70, 71, 72, 73, 74, 75, 0, 76, 77, + 78, 79, 80, 81, 101, 65, 66, 67, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, + 65, 66, 67, 0, 0, 0, 0, 68, 69, 70, + 71, 72, 73, 74, 75, 0, 76, 77, 78, 79, + 80, 81, 68, 69, 70, 71, 72, 73, 74, 75, + 0, 76, 77, 78, 79, 80, 81, 103, 65, 66, + 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 104, 65, 66, 67, 0, 0, 0, 0, + 68, 69, 70, 71, 72, 73, 74, 75, 0, 76, + 77, 78, 79, 80, 81, 68, 69, 70, 71, 72, + 73, 74, 75, 0, 76, 77, 78, 79, 80, 81, + 109, 65, 66, 67, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 110, 65, 66, 67, 0, + 0, 0, 0, 68, 69, 70, 71, 72, 73, 74, + 75, 0, 76, 77, 78, 79, 80, 81, 68, 69, + 70, 71, 72, 73, 74, 75, 0, 76, 77, 78, + 79, 80, 81, 111, 65, 66, 67, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 112, 65, + 66, 67, 0, 0, 0, 0, 68, 69, 70, 71, + 72, 73, 74, 75, 0, 76, 77, 78, 79, 80, + 81, 68, 69, 70, 71, 72, 73, 74, 75, 0, + 76, 77, 78, 79, 80, 81, 113, 65, 66, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 97, 65, 66, 0, 0, 0, 0, 0, - 67, 68, 69, 70, 71, 72, 73, 74, 0, 75, - 76, 77, 78, 79, 80, 67, 68, 69, 70, 71, - 72, 73, 74, 0, 75, 76, 77, 78, 79, 80, - 98, 65, 66, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 99, 65, 66, 0, 0, - 0, 0, 0, 67, 68, 69, 70, 71, 72, 73, - 74, 0, 75, 76, 77, 78, 79, 80, 67, 68, - 69, 70, 71, 72, 73, 74, 0, 75, 76, 77, - 78, 79, 80, 100, 65, 66, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 101, 65, - 66, 0, 0, 0, 0, 0, 67, 68, 69, 70, - 71, 72, 73, 74, 0, 75, 76, 77, 78, 79, - 80, 67, 68, 69, 70, 71, 72, 73, 74, 0, - 75, 76, 77, 78, 79, 80, 102, 65, 66, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 103, 65, 66, 0, 0, 0, 0, 0, 67, - 68, 69, 70, 71, 72, 73, 74, 0, 75, 76, - 77, 78, 79, 80, 67, 68, 69, 70, 71, 72, - 73, 74, 0, 75, 76, 77, 78, 79, 80, 108, - 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 109, 65, 66, 0, 0, 0, - 0, 0, 67, 68, 69, 70, 71, 72, 73, 74, - 0, 75, 76, 77, 78, 79, 80, 67, 68, 69, - 70, 71, 72, 73, 74, 0, 75, 76, 77, 78, - 79, 80, 110, 65, 66, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 111, 65, 66, - 0, 0, 0, 0, 0, 67, 68, 69, 70, 71, - 72, 73, 74, 0, 75, 76, 77, 78, 79, 80, - 67, 68, 69, 70, 71, 72, 73, 74, 0, 75, - 76, 77, 78, 79, 80, 112, 65, 66, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 113, 65, 66, 0, 0, 0, 0, 0, 67, 68, - 69, 70, 71, 72, 73, 74, 0, 75, 76, 77, - 78, 79, 80, 67, 68, 69, 70, 71, 72, 73, - 74, 0, 75, 76, 77, 78, 79, 80, 117, 65, - 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 122, 65, 66, 0, 0, 0, 0, - 0, 67, 68, 69, 70, 71, 72, 73, 74, 0, - 75, 76, 77, 78, 79, 80, 67, 68, 69, 70, - 71, 72, 73, 74, 0, 75, 76, 77, 78, 79, - 80, 123, 65, 66, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 125, 65, 66, 0, - 0, 0, 0, 0, 67, 68, 69, 70, 71, 72, - 73, 74, 0, 75, 76, 77, 78, 79, 80, 67, - 68, 69, 70, 71, 72, 73, 74, 0, 75, 76, - 77, 78, 79, 80 + 0, 114, 65, 66, 67, 0, 0, 0, 0, 68, + 69, 70, 71, 72, 73, 74, 75, 0, 76, 77, + 78, 79, 80, 81, 68, 69, 70, 71, 72, 73, + 74, 75, 0, 76, 77, 78, 79, 80, 81, 118, + 65, 66, 67, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 123, 65, 66, 67, 0, 0, + 0, 0, 68, 69, 70, 71, 72, 73, 74, 75, + 0, 76, 77, 78, 79, 80, 81, 68, 69, 70, + 71, 72, 73, 74, 75, 0, 76, 77, 78, 79, + 80, 81, 124, 65, 66, 67, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 126, 65, 66, + 67, 0, 0, 0, 0, 68, 69, 70, 71, 72, + 73, 74, 75, 0, 76, 77, 78, 79, 80, 81, + 68, 69, 70, 71, 72, 73, 74, 75, 0, 76, + 77, 78, 79, 80, 81 }; static const yytype_int8 yycheck[] = @@ -745,62 +747,62 @@ static const yytype_int8 yycheck[] = 48, 49, 32, 37, 32, 53, 54, 55, 56, 57, 58, 0, 1, 3, 3, 33, 29, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 32, -1, 33, - 88, 33, 33, 33, 28, 34, 35, 36, 37, 38, - 39, 40, 3, 4, 5, 26, 33, 28, 33, 33, - 33, 33, 33, 33, 33, 30, 33, 115, 116, 3, - 4, 5, -1, 121, -1, 26, 27, 28, 29, 30, + 19, 20, 21, 22, 23, 24, 25, 32, 30, 33, + 33, 89, 33, 33, 28, 34, 35, 36, 37, 38, + 39, 40, 3, 4, 5, 6, 26, 33, 28, 33, + 33, 33, 33, 33, 33, 33, 33, -1, 116, 117, + 3, 4, 5, 6, 122, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, - -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, + -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, + 33, -1, 35, 36, 37, 38, 39, 40, 3, 4, + 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 3, 4, 5, 6, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, -1, + 35, 36, 37, 38, 39, 40, 26, 27, 28, 29, + 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, + 40, 3, 4, 5, 6, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3, 4, 5, 6, + -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, + 32, 33, -1, 35, 36, 37, 38, 39, 40, 26, + 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, + 37, 38, 39, 40, 3, 4, 5, 6, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, + 4, 5, 6, -1, -1, -1, -1, 26, 27, 28, + 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, + 39, 40, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, 3, 4, 5, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 3, 4, 5, -1, -1, -1, -1, -1, + 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 3, 4, 5, 6, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, - 3, 4, 5, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 3, 4, 5, -1, -1, + 3, 4, 5, 6, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 3, 4, 5, 6, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, - 38, 39, 40, 3, 4, 5, -1, -1, -1, -1, + 38, 39, 40, 3, 4, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 4, - 5, -1, -1, -1, -1, -1, 26, 27, 28, 29, + 5, 6, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, 26, 27, 28, 29, 30, 31, 32, 33, -1, - 35, 36, 37, 38, 39, 40, 3, 4, 5, -1, + 35, 36, 37, 38, 39, 40, 3, 4, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 3, 4, 5, -1, -1, -1, -1, -1, 26, + -1, 3, 4, 5, 6, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, 3, - 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 3, 4, 5, -1, -1, -1, + 4, 5, 6, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 3, 4, 5, 6, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, - 39, 40, 3, 4, 5, -1, -1, -1, -1, -1, + 39, 40, 3, 4, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 4, 5, - -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, + 6, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, - 36, 37, 38, 39, 40, 3, 4, 5, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 3, 4, 5, -1, -1, -1, -1, -1, 26, 27, - 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, - 38, 39, 40, 26, 27, 28, 29, 30, 31, 32, - 33, -1, 35, 36, 37, 38, 39, 40, 3, 4, - 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 3, 4, 5, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, -1, - 35, 36, 37, 38, 39, 40, 26, 27, 28, 29, - 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, - 40, 3, 4, 5, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3, 4, 5, -1, - -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, - 32, 33, -1, 35, 36, 37, 38, 39, 40, 26, - 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, - 37, 38, 39, 40 + 36, 37, 38, 39, 40 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -813,13 +815,13 @@ static const yytype_uint8 yystos[] = 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 3, 32, 53, 37, 32, 3, 33, 33, 29, 26, 28, 33, 32, 33, 33, 33, 33, 53, - 53, 53, 53, 53, 3, 4, 5, 26, 27, 28, - 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, - 40, 54, 53, 53, 53, 53, 33, 33, 33, 53, - 53, 53, 53, 53, 53, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 27, 30, 28, 53, 3, 3, - 3, 3, 3, 3, 33, 33, 33, 3, 30, 53, - 53, 33, 3, 3, 53, 3 + 53, 53, 53, 53, 3, 4, 5, 6, 26, 27, + 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, + 39, 40, 54, 53, 53, 53, 53, 33, 33, 33, + 53, 53, 53, 53, 53, 53, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 27, 30, 28, 53, 3, + 3, 3, 3, 3, 3, 33, 33, 33, 3, 30, + 53, 53, 33, 3, 3, 53, 3 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ @@ -831,7 +833,7 @@ static const yytype_uint8 yyr1[] = 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54 + 54, 54, 54, 54, 54 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ @@ -843,7 +845,7 @@ static const yytype_uint8 yyr2[] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1 + 1, 1, 1, 1, 1 }; @@ -930,7 +932,9 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, yy if (yytype < YYNTOKENS) YYPRINT (yyo, yytoknum[yytype], *yyvaluep); # endif + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -1368,6 +1372,8 @@ yynewstate: | yynewstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); *yyssp = (yytype_int16) yystate; if (yyss + yystacksize - 1 <= yyssp) @@ -1430,8 +1436,6 @@ yysetstate: } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - if (yystate == YYFINAL) YYACCEPT; @@ -1499,7 +1503,6 @@ yybackup: YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END - goto yynewstate; @@ -1534,27 +1537,27 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 4: -#line 104 "cmFortranParser.y" /* yacc.c:1652 */ + case 4: +#line 104 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_SetInInterface(parser, true); } -#line 1544 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1547 "cmFortranParser.cxx" break; case 5: -#line 108 "cmFortranParser.y" /* yacc.c:1652 */ +#line 108 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleUse(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1554 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1557 "cmFortranParser.cxx" break; case 6: -#line 113 "cmFortranParser.y" /* yacc.c:1652 */ +#line 113 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); if (cmsysString_strcasecmp((yyvsp[-2].string), "function") != 0 && @@ -1564,22 +1567,22 @@ yyreduce: } free((yyvsp[-2].string)); } -#line 1568 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1571 "cmFortranParser.cxx" break; case 7: -#line 122 "cmFortranParser.y" /* yacc.c:1652 */ +#line 122 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleSubmodule(parser, (yyvsp[-4].string), (yyvsp[-2].string)); free((yyvsp[-4].string)); free((yyvsp[-2].string)); } -#line 1579 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1582 "cmFortranParser.cxx" break; case 8: -#line 128 "cmFortranParser.y" /* yacc.c:1652 */ +#line 128 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleSubmoduleNested(parser, (yyvsp[-6].string), (yyvsp[-4].string), (yyvsp[-2].string)); @@ -1587,40 +1590,40 @@ yyreduce: free((yyvsp[-4].string)); free((yyvsp[-2].string)); } -#line 1591 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1594 "cmFortranParser.cxx" break; case 9: -#line 135 "cmFortranParser.y" /* yacc.c:1652 */ +#line 135 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_SetInInterface(parser, true); free((yyvsp[-2].string)); } -#line 1601 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1604 "cmFortranParser.cxx" break; case 10: -#line 140 "cmFortranParser.y" /* yacc.c:1652 */ +#line 140 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_SetInInterface(parser, false); } -#line 1610 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1613 "cmFortranParser.cxx" break; case 11: -#line 144 "cmFortranParser.y" /* yacc.c:1652 */ +#line 144 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleUse(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1620 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1623 "cmFortranParser.cxx" break; case 12: -#line 149 "cmFortranParser.y" /* yacc.c:1652 */ +#line 149 "cmFortranParser.y" { if (cmsysString_strcasecmp((yyvsp[-4].string), "non_intrinsic") == 0) { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); @@ -1629,139 +1632,140 @@ yyreduce: free((yyvsp[-4].string)); free((yyvsp[-2].string)); } -#line 1633 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1636 "cmFortranParser.cxx" break; case 13: -#line 157 "cmFortranParser.y" /* yacc.c:1652 */ +#line 157 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1643 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1646 "cmFortranParser.cxx" break; case 14: -#line 162 "cmFortranParser.y" /* yacc.c:1652 */ +#line 162 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1653 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1656 "cmFortranParser.cxx" break; case 15: -#line 167 "cmFortranParser.y" /* yacc.c:1652 */ +#line 167 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1663 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1666 "cmFortranParser.cxx" break; case 16: -#line 172 "cmFortranParser.y" /* yacc.c:1652 */ +#line 172 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1673 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1676 "cmFortranParser.cxx" break; case 17: -#line 177 "cmFortranParser.y" /* yacc.c:1652 */ +#line 177 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleDefine(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1683 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1686 "cmFortranParser.cxx" break; case 18: -#line 182 "cmFortranParser.y" /* yacc.c:1652 */ +#line 182 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleUndef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1693 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1696 "cmFortranParser.cxx" break; case 19: -#line 187 "cmFortranParser.y" /* yacc.c:1652 */ +#line 187 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1703 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1706 "cmFortranParser.cxx" break; case 20: -#line 192 "cmFortranParser.y" /* yacc.c:1652 */ +#line 192 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1713 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1716 "cmFortranParser.cxx" break; case 21: -#line 197 "cmFortranParser.y" /* yacc.c:1652 */ +#line 197 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIf(parser); } -#line 1722 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1725 "cmFortranParser.cxx" break; case 22: -#line 201 "cmFortranParser.y" /* yacc.c:1652 */ +#line 201 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleElif(parser); } -#line 1731 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1734 "cmFortranParser.cxx" break; case 23: -#line 205 "cmFortranParser.y" /* yacc.c:1652 */ +#line 205 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleElse(parser); } -#line 1740 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1743 "cmFortranParser.cxx" break; case 24: -#line 209 "cmFortranParser.y" /* yacc.c:1652 */ +#line 209 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleEndif(parser); } -#line 1749 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1752 "cmFortranParser.cxx" break; case 48: -#line 231 "cmFortranParser.y" /* yacc.c:1652 */ +#line 231 "cmFortranParser.y" { free ((yyvsp[0].string)); } -#line 1755 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1758 "cmFortranParser.cxx" break; case 55: -#line 238 "cmFortranParser.y" /* yacc.c:1652 */ +#line 238 "cmFortranParser.y" { free ((yyvsp[0].string)); } -#line 1761 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1764 "cmFortranParser.cxx" break; -#line 1765 "cmFortranParser.cxx" /* yacc.c:1652 */ +#line 1768 "cmFortranParser.cxx" + default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1994,6 +1998,6 @@ yyreturn: #endif return yyresult; } -#line 249 "cmFortranParser.y" /* yacc.c:1918 */ +#line 250 "cmFortranParser.y" /* End of grammar */ diff --git a/Source/LexerParser/cmFortranParser.y b/Source/LexerParser/cmFortranParser.y index 87f3e0a..1b54dd9 100644 --- a/Source/LexerParser/cmFortranParser.y +++ b/Source/LexerParser/cmFortranParser.y @@ -244,6 +244,7 @@ misc_code: | RPAREN | COMMA | UNTERMINATED_STRING +| CPP_LINE_DIRECTIVE ; %% diff --git a/Source/LexerParser/cmFortranParserTokens.h b/Source/LexerParser/cmFortranParserTokens.h index 0da4c1c..f66a15c 100644 --- a/Source/LexerParser/cmFortranParserTokens.h +++ b/Source/LexerParser/cmFortranParserTokens.h @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.3.2. */ +/* A Bison parser, made by GNU Bison 3.4.2. */ /* Bison interface for Yacc-like parsers in C @@ -131,16 +131,15 @@ extern int cmFortran_yydebug; /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - union YYSTYPE { -#line 73 "cmFortranParser.y" /* yacc.c:1921 */ +#line 73 "cmFortranParser.y" char* string; -#line 142 "cmFortranParserTokens.h" /* yacc.c:1921 */ -}; +#line 141 "cmFortranParserTokens.h" +}; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 diff --git a/Source/LexerParser/cmGccDepfileLexer.cxx b/Source/LexerParser/cmGccDepfileLexer.cxx new file mode 100644 index 0000000..a98969d --- /dev/null +++ b/Source/LexerParser/cmGccDepfileLexer.cxx @@ -0,0 +1,2210 @@ +#include "cmStandardLexer.h" + +#define FLEXINT_H 1 +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define cmGccDepfile_yy_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer cmGccDepfile_yy_create_buffer +#endif + +#ifdef yy_delete_buffer +#define cmGccDepfile_yy_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer cmGccDepfile_yy_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define cmGccDepfile_yy_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer cmGccDepfile_yy_scan_buffer +#endif + +#ifdef yy_scan_string +#define cmGccDepfile_yy_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string cmGccDepfile_yy_scan_string +#endif + +#ifdef yy_scan_bytes +#define cmGccDepfile_yy_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes cmGccDepfile_yy_scan_bytes +#endif + +#ifdef yy_init_buffer +#define cmGccDepfile_yy_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer cmGccDepfile_yy_init_buffer +#endif + +#ifdef yy_flush_buffer +#define cmGccDepfile_yy_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer cmGccDepfile_yy_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define cmGccDepfile_yy_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state cmGccDepfile_yy_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define cmGccDepfile_yy_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer cmGccDepfile_yy_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define cmGccDepfile_yypush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state cmGccDepfile_yypush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define cmGccDepfile_yypop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state cmGccDepfile_yypop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define cmGccDepfile_yyensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack cmGccDepfile_yyensure_buffer_stack +#endif + +#ifdef yylex +#define cmGccDepfile_yylex_ALREADY_DEFINED +#else +#define yylex cmGccDepfile_yylex +#endif + +#ifdef yyrestart +#define cmGccDepfile_yyrestart_ALREADY_DEFINED +#else +#define yyrestart cmGccDepfile_yyrestart +#endif + +#ifdef yylex_init +#define cmGccDepfile_yylex_init_ALREADY_DEFINED +#else +#define yylex_init cmGccDepfile_yylex_init +#endif + +#ifdef yylex_init_extra +#define cmGccDepfile_yylex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra cmGccDepfile_yylex_init_extra +#endif + +#ifdef yylex_destroy +#define cmGccDepfile_yylex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy cmGccDepfile_yylex_destroy +#endif + +#ifdef yyget_debug +#define cmGccDepfile_yyget_debug_ALREADY_DEFINED +#else +#define yyget_debug cmGccDepfile_yyget_debug +#endif + +#ifdef yyset_debug +#define cmGccDepfile_yyset_debug_ALREADY_DEFINED +#else +#define yyset_debug cmGccDepfile_yyset_debug +#endif + +#ifdef yyget_extra +#define cmGccDepfile_yyget_extra_ALREADY_DEFINED +#else +#define yyget_extra cmGccDepfile_yyget_extra +#endif + +#ifdef yyset_extra +#define cmGccDepfile_yyset_extra_ALREADY_DEFINED +#else +#define yyset_extra cmGccDepfile_yyset_extra +#endif + +#ifdef yyget_in +#define cmGccDepfile_yyget_in_ALREADY_DEFINED +#else +#define yyget_in cmGccDepfile_yyget_in +#endif + +#ifdef yyset_in +#define cmGccDepfile_yyset_in_ALREADY_DEFINED +#else +#define yyset_in cmGccDepfile_yyset_in +#endif + +#ifdef yyget_out +#define cmGccDepfile_yyget_out_ALREADY_DEFINED +#else +#define yyget_out cmGccDepfile_yyget_out +#endif + +#ifdef yyset_out +#define cmGccDepfile_yyset_out_ALREADY_DEFINED +#else +#define yyset_out cmGccDepfile_yyset_out +#endif + +#ifdef yyget_leng +#define cmGccDepfile_yyget_leng_ALREADY_DEFINED +#else +#define yyget_leng cmGccDepfile_yyget_leng +#endif + +#ifdef yyget_text +#define cmGccDepfile_yyget_text_ALREADY_DEFINED +#else +#define yyget_text cmGccDepfile_yyget_text +#endif + +#ifdef yyget_lineno +#define cmGccDepfile_yyget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno cmGccDepfile_yyget_lineno +#endif + +#ifdef yyset_lineno +#define cmGccDepfile_yyset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno cmGccDepfile_yyset_lineno +#endif + +#ifdef yyget_column +#define cmGccDepfile_yyget_column_ALREADY_DEFINED +#else +#define yyget_column cmGccDepfile_yyget_column +#endif + +#ifdef yyset_column +#define cmGccDepfile_yyset_column_ALREADY_DEFINED +#else +#define yyset_column cmGccDepfile_yyset_column +#endif + +#ifdef yywrap +#define cmGccDepfile_yywrap_ALREADY_DEFINED +#else +#define yywrap cmGccDepfile_yywrap +#endif + +#ifdef yyalloc +#define cmGccDepfile_yyalloc_ALREADY_DEFINED +#else +#define yyalloc cmGccDepfile_yyalloc +#endif + +#ifdef yyrealloc +#define cmGccDepfile_yyrealloc_ALREADY_DEFINED +#else +#define yyrealloc cmGccDepfile_yyrealloc +#endif + +#ifdef yyfree +#define cmGccDepfile_yyfree_ALREADY_DEFINED +#else +#define yyfree cmGccDepfile_yyfree +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define cmGccDepfile_yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 11 +#define YY_END_OF_BUFFER 12 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[26] = + { 0, + 0, 0, 12, 10, 8, 6, 10, 9, 10, 10, + 10, 8, 0, 6, 9, 1, 7, 5, 0, 3, + 2, 0, 4, 0, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5, 6, 1, 7, 8, 6, 1, 1, 6, + 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 9, 1, 1, + 6, 1, 1, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 10, 6, 1, 6, 1, 6, 6, 6, 6, + + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 1, 6, 6, 1, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6 + } ; + +static const YY_CHAR yy_meta[11] = + { 0, + 1, 2, 1, 1, 2, 1, 1, 1, 1, 3 + } ; + +static const flex_int16_t yy_base[28] = + { 0, + 0, 0, 29, 35, 18, 35, 22, 18, 15, 0, + 8, 12, 16, 35, 11, 35, 0, 35, 13, 35, + 35, 16, 35, 22, 35, 31, 12 + } ; + +static const flex_int16_t yy_def[28] = + { 0, + 25, 1, 25, 25, 26, 25, 25, 25, 25, 27, + 25, 26, 25, 25, 25, 25, 27, 25, 25, 25, + 25, 25, 25, 25, 0, 25, 25 + } ; + +static const flex_int16_t yy_nxt[46] = + { 0, + 4, 5, 6, 7, 5, 8, 4, 9, 10, 11, + 18, 19, 20, 17, 21, 18, 15, 22, 18, 19, + 23, 13, 16, 15, 14, 24, 20, 13, 25, 25, + 25, 22, 12, 12, 3, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25 + } ; + +static const flex_int16_t yy_chk[46] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 11, 11, 11, 27, 11, 19, 15, 11, 13, 13, + 22, 12, 9, 8, 7, 22, 24, 5, 3, 0, + 0, 24, 26, 26, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +/* IWYU pragma: no_forward_declare yyguts_t */ + +#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */ + +#include <cmGccDepfileLexerHelper.h> +#include <string> + +#define INITIAL 0 + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + }; /* end struct yyguts_t */ + +static int yy_init_globals ( yyscan_t yyscanner ); + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + + static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner); + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (yyscan_t yyscanner); + +#define YY_DECL int yylex (yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 26 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 35 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +{ + // Unescape the dollar sign. + yyextra->addToCurrentPath("$"); + } + YY_BREAK +case 2: +YY_RULE_SETUP +{ + // Unescape the hash. + yyextra->addToCurrentPath("#"); + } + YY_BREAK +case 3: +YY_RULE_SETUP +{ + // 2N+1 backslashes plus space -> N backslashes plus space. + size_t c = (strlen(yytext) - 1) / 2; + std::string s(c, '\\'); + s.push_back(' '); + yyextra->addToCurrentPath(s.c_str()); + } + YY_BREAK +case 4: +YY_RULE_SETUP +{ + // 2N backslashes plus space -> 2N backslashes, end of filename. + yytext[strlen(yytext) - 1] = 0; + yyextra->addToCurrentPath(yytext); + yyextra->newDependency(); + } + YY_BREAK +case 5: +/* rule 5 can match eol */ +YY_RULE_SETUP +{ + // A line continuation ends the current file name. + yyextra->newDependency(); + } + YY_BREAK +case 6: +/* rule 6 can match eol */ +YY_RULE_SETUP +{ + // A newline ends the current file name and the current rule. + yyextra->newEntry(); + } + YY_BREAK +case 7: +YY_RULE_SETUP +{ + // A colon followed by space ends the rules and starts a new dependency. + yyextra->newDependency(); + } + YY_BREAK +case 8: +YY_RULE_SETUP +{ + // Rules and dependencies are separated by blocks of whitespace. + yyextra->newRuleOrDependency(); + } + YY_BREAK +case 9: +YY_RULE_SETUP +{ + // Got a span of plain text. + yyextra->addToCurrentPath(yytext); + } + YY_BREAK +case 10: +YY_RULE_SETUP +{ + // Got an otherwise unmatched character. + yyextra->addToCurrentPath(yytext); + } + YY_BREAK +case 11: +YY_RULE_SETUP +ECHO; + YY_BREAK +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 26 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 26 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 25); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + + static void yyunput (int c, char * yy_bp , yyscan_t yyscanner) +{ + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_cp = yyg->yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yyg->yy_hold_char; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + int number_to_move = yyg->yy_n_chars + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + yyg->yytext_ptr = yy_bp; + yyg->yy_hold_char = *yy_cp; + yyg->yy_c_buf_p = yy_cp; +} + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +/*--------------------------------------------------------------------------*/ + +#endif /* __clang_analyzer__ */ diff --git a/Source/LexerParser/cmGccDepfileLexer.h b/Source/LexerParser/cmGccDepfileLexer.h new file mode 100644 index 0000000..7d34060 --- /dev/null +++ b/Source/LexerParser/cmGccDepfileLexer.h @@ -0,0 +1,687 @@ +#ifndef cmGccDepfile_yyHEADER_H +#define cmGccDepfile_yyHEADER_H 1 +#define cmGccDepfile_yyIN_HEADER 1 + +#define FLEXINT_H 1 +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define cmGccDepfile_yy_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer cmGccDepfile_yy_create_buffer +#endif + +#ifdef yy_delete_buffer +#define cmGccDepfile_yy_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer cmGccDepfile_yy_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define cmGccDepfile_yy_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer cmGccDepfile_yy_scan_buffer +#endif + +#ifdef yy_scan_string +#define cmGccDepfile_yy_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string cmGccDepfile_yy_scan_string +#endif + +#ifdef yy_scan_bytes +#define cmGccDepfile_yy_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes cmGccDepfile_yy_scan_bytes +#endif + +#ifdef yy_init_buffer +#define cmGccDepfile_yy_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer cmGccDepfile_yy_init_buffer +#endif + +#ifdef yy_flush_buffer +#define cmGccDepfile_yy_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer cmGccDepfile_yy_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define cmGccDepfile_yy_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state cmGccDepfile_yy_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define cmGccDepfile_yy_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer cmGccDepfile_yy_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define cmGccDepfile_yypush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state cmGccDepfile_yypush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define cmGccDepfile_yypop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state cmGccDepfile_yypop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define cmGccDepfile_yyensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack cmGccDepfile_yyensure_buffer_stack +#endif + +#ifdef yylex +#define cmGccDepfile_yylex_ALREADY_DEFINED +#else +#define yylex cmGccDepfile_yylex +#endif + +#ifdef yyrestart +#define cmGccDepfile_yyrestart_ALREADY_DEFINED +#else +#define yyrestart cmGccDepfile_yyrestart +#endif + +#ifdef yylex_init +#define cmGccDepfile_yylex_init_ALREADY_DEFINED +#else +#define yylex_init cmGccDepfile_yylex_init +#endif + +#ifdef yylex_init_extra +#define cmGccDepfile_yylex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra cmGccDepfile_yylex_init_extra +#endif + +#ifdef yylex_destroy +#define cmGccDepfile_yylex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy cmGccDepfile_yylex_destroy +#endif + +#ifdef yyget_debug +#define cmGccDepfile_yyget_debug_ALREADY_DEFINED +#else +#define yyget_debug cmGccDepfile_yyget_debug +#endif + +#ifdef yyset_debug +#define cmGccDepfile_yyset_debug_ALREADY_DEFINED +#else +#define yyset_debug cmGccDepfile_yyset_debug +#endif + +#ifdef yyget_extra +#define cmGccDepfile_yyget_extra_ALREADY_DEFINED +#else +#define yyget_extra cmGccDepfile_yyget_extra +#endif + +#ifdef yyset_extra +#define cmGccDepfile_yyset_extra_ALREADY_DEFINED +#else +#define yyset_extra cmGccDepfile_yyset_extra +#endif + +#ifdef yyget_in +#define cmGccDepfile_yyget_in_ALREADY_DEFINED +#else +#define yyget_in cmGccDepfile_yyget_in +#endif + +#ifdef yyset_in +#define cmGccDepfile_yyset_in_ALREADY_DEFINED +#else +#define yyset_in cmGccDepfile_yyset_in +#endif + +#ifdef yyget_out +#define cmGccDepfile_yyget_out_ALREADY_DEFINED +#else +#define yyget_out cmGccDepfile_yyget_out +#endif + +#ifdef yyset_out +#define cmGccDepfile_yyset_out_ALREADY_DEFINED +#else +#define yyset_out cmGccDepfile_yyset_out +#endif + +#ifdef yyget_leng +#define cmGccDepfile_yyget_leng_ALREADY_DEFINED +#else +#define yyget_leng cmGccDepfile_yyget_leng +#endif + +#ifdef yyget_text +#define cmGccDepfile_yyget_text_ALREADY_DEFINED +#else +#define yyget_text cmGccDepfile_yyget_text +#endif + +#ifdef yyget_lineno +#define cmGccDepfile_yyget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno cmGccDepfile_yyget_lineno +#endif + +#ifdef yyset_lineno +#define cmGccDepfile_yyset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno cmGccDepfile_yyset_lineno +#endif + +#ifdef yyget_column +#define cmGccDepfile_yyget_column_ALREADY_DEFINED +#else +#define yyget_column cmGccDepfile_yyget_column +#endif + +#ifdef yyset_column +#define cmGccDepfile_yyset_column_ALREADY_DEFINED +#else +#define yyset_column cmGccDepfile_yyset_column +#endif + +#ifdef yywrap +#define cmGccDepfile_yywrap_ALREADY_DEFINED +#else +#define yywrap cmGccDepfile_yywrap +#endif + +#ifdef yyalloc +#define cmGccDepfile_yyalloc_ALREADY_DEFINED +#else +#define yyalloc cmGccDepfile_yyalloc +#endif + +#ifdef yyrealloc +#define cmGccDepfile_yyrealloc_ALREADY_DEFINED +#else +#define yyrealloc cmGccDepfile_yyrealloc +#endif + +#ifdef yyfree +#define cmGccDepfile_yyfree_ALREADY_DEFINED +#else +#define yyfree cmGccDepfile_yyfree +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +/* Begin user sect3 */ + +#define cmGccDepfile_yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP + +#define yytext_ptr yytext_r + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 + +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (yyscan_t yyscanner); + +#define YY_DECL int yylex (yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#ifndef cmGccDepfile_yy_create_buffer_ALREADY_DEFINED +#undef yy_create_buffer +#endif +#ifndef cmGccDepfile_yy_delete_buffer_ALREADY_DEFINED +#undef yy_delete_buffer +#endif +#ifndef cmGccDepfile_yy_scan_buffer_ALREADY_DEFINED +#undef yy_scan_buffer +#endif +#ifndef cmGccDepfile_yy_scan_string_ALREADY_DEFINED +#undef yy_scan_string +#endif +#ifndef cmGccDepfile_yy_scan_bytes_ALREADY_DEFINED +#undef yy_scan_bytes +#endif +#ifndef cmGccDepfile_yy_init_buffer_ALREADY_DEFINED +#undef yy_init_buffer +#endif +#ifndef cmGccDepfile_yy_flush_buffer_ALREADY_DEFINED +#undef yy_flush_buffer +#endif +#ifndef cmGccDepfile_yy_load_buffer_state_ALREADY_DEFINED +#undef yy_load_buffer_state +#endif +#ifndef cmGccDepfile_yy_switch_to_buffer_ALREADY_DEFINED +#undef yy_switch_to_buffer +#endif +#ifndef cmGccDepfile_yypush_buffer_state_ALREADY_DEFINED +#undef yypush_buffer_state +#endif +#ifndef cmGccDepfile_yypop_buffer_state_ALREADY_DEFINED +#undef yypop_buffer_state +#endif +#ifndef cmGccDepfile_yyensure_buffer_stack_ALREADY_DEFINED +#undef yyensure_buffer_stack +#endif +#ifndef cmGccDepfile_yylex_ALREADY_DEFINED +#undef yylex +#endif +#ifndef cmGccDepfile_yyrestart_ALREADY_DEFINED +#undef yyrestart +#endif +#ifndef cmGccDepfile_yylex_init_ALREADY_DEFINED +#undef yylex_init +#endif +#ifndef cmGccDepfile_yylex_init_extra_ALREADY_DEFINED +#undef yylex_init_extra +#endif +#ifndef cmGccDepfile_yylex_destroy_ALREADY_DEFINED +#undef yylex_destroy +#endif +#ifndef cmGccDepfile_yyget_debug_ALREADY_DEFINED +#undef yyget_debug +#endif +#ifndef cmGccDepfile_yyset_debug_ALREADY_DEFINED +#undef yyset_debug +#endif +#ifndef cmGccDepfile_yyget_extra_ALREADY_DEFINED +#undef yyget_extra +#endif +#ifndef cmGccDepfile_yyset_extra_ALREADY_DEFINED +#undef yyset_extra +#endif +#ifndef cmGccDepfile_yyget_in_ALREADY_DEFINED +#undef yyget_in +#endif +#ifndef cmGccDepfile_yyset_in_ALREADY_DEFINED +#undef yyset_in +#endif +#ifndef cmGccDepfile_yyget_out_ALREADY_DEFINED +#undef yyget_out +#endif +#ifndef cmGccDepfile_yyset_out_ALREADY_DEFINED +#undef yyset_out +#endif +#ifndef cmGccDepfile_yyget_leng_ALREADY_DEFINED +#undef yyget_leng +#endif +#ifndef cmGccDepfile_yyget_text_ALREADY_DEFINED +#undef yyget_text +#endif +#ifndef cmGccDepfile_yyget_lineno_ALREADY_DEFINED +#undef yyget_lineno +#endif +#ifndef cmGccDepfile_yyset_lineno_ALREADY_DEFINED +#undef yyset_lineno +#endif +#ifndef cmGccDepfile_yyget_column_ALREADY_DEFINED +#undef yyget_column +#endif +#ifndef cmGccDepfile_yyset_column_ALREADY_DEFINED +#undef yyset_column +#endif +#ifndef cmGccDepfile_yywrap_ALREADY_DEFINED +#undef yywrap +#endif +#ifndef cmGccDepfile_yyget_lval_ALREADY_DEFINED +#undef yyget_lval +#endif +#ifndef cmGccDepfile_yyset_lval_ALREADY_DEFINED +#undef yyset_lval +#endif +#ifndef cmGccDepfile_yyget_lloc_ALREADY_DEFINED +#undef yyget_lloc +#endif +#ifndef cmGccDepfile_yyset_lloc_ALREADY_DEFINED +#undef yyset_lloc +#endif +#ifndef cmGccDepfile_yyalloc_ALREADY_DEFINED +#undef yyalloc +#endif +#ifndef cmGccDepfile_yyrealloc_ALREADY_DEFINED +#undef yyrealloc +#endif +#ifndef cmGccDepfile_yyfree_ALREADY_DEFINED +#undef yyfree +#endif +#ifndef cmGccDepfile_yytext_ALREADY_DEFINED +#undef yytext +#endif +#ifndef cmGccDepfile_yyleng_ALREADY_DEFINED +#undef yyleng +#endif +#ifndef cmGccDepfile_yyin_ALREADY_DEFINED +#undef yyin +#endif +#ifndef cmGccDepfile_yyout_ALREADY_DEFINED +#undef yyout +#endif +#ifndef cmGccDepfile_yy_flex_debug_ALREADY_DEFINED +#undef yy_flex_debug +#endif +#ifndef cmGccDepfile_yylineno_ALREADY_DEFINED +#undef yylineno +#endif +#ifndef cmGccDepfile_yytables_fload_ALREADY_DEFINED +#undef yytables_fload +#endif +#ifndef cmGccDepfile_yytables_destroy_ALREADY_DEFINED +#undef yytables_destroy +#endif +#ifndef cmGccDepfile_yyTABLES_NAME_ALREADY_DEFINED +#undef yyTABLES_NAME +#endif + +#undef cmGccDepfile_yyIN_HEADER +#endif /* cmGccDepfile_yyHEADER_H */ diff --git a/Source/LexerParser/cmGccDepfileLexer.in.l b/Source/LexerParser/cmGccDepfileLexer.in.l new file mode 100644 index 0000000..08f8577 --- /dev/null +++ b/Source/LexerParser/cmGccDepfileLexer.in.l @@ -0,0 +1,72 @@ +%{ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +/* IWYU pragma: no_forward_declare yyguts_t */ + +#ifndef __clang_analyzer__ /* Suppress clang scan-build warnings */ + +#include <cmGccDepfileLexerHelper.h> +#include <string> +%} + +%option prefix="cmGccDepfile_yy" +%option noyywrap +%option reentrant +%pointer + +WSPACE [ \t] +NEWLINE \r?\n + +%% +\${2} { + // Unescape the dollar sign. + yyextra->addToCurrentPath("$"); + } +\\# { + // Unescape the hash. + yyextra->addToCurrentPath("#"); + } +(\\\\)*\\[ ] { + // 2N+1 backslashes plus space -> N backslashes plus space. + size_t c = (strlen(yytext) - 1) / 2; + std::string s(c, '\\'); + s.push_back(' '); + yyextra->addToCurrentPath(s.c_str()); + } +(\\\\)+[ ] { + // 2N backslashes plus space -> 2N backslashes, end of filename. + yytext[strlen(yytext) - 1] = 0; + yyextra->addToCurrentPath(yytext); + yyextra->newDependency(); + } +{WSPACE}*\\{NEWLINE} { + // A line continuation ends the current file name. + yyextra->newDependency(); + } +{NEWLINE} { + // A newline ends the current file name and the current rule. + yyextra->newEntry(); + } +:{WSPACE}+ { + // A colon followed by space ends the rules and starts a new dependency. + yyextra->newDependency(); + } +{WSPACE}+ { + // Rules and dependencies are separated by blocks of whitespace. + yyextra->newRuleOrDependency(); + } +[a-zA-Z0-9+,/_.~()}{%=@\x5B\x5D!\x80-\xFF-]+ { + // Got a span of plain text. + yyextra->addToCurrentPath(yytext); + } +. { + // Got an otherwise unmatched character. + yyextra->addToCurrentPath(yytext); + } + +%% + +/*--------------------------------------------------------------------------*/ + +#endif /* __clang_analyzer__ */ diff --git a/Source/LexerParser/cmListFileLexer.c b/Source/LexerParser/cmListFileLexer.c index 15dcda0..ec7424c 100644 --- a/Source/LexerParser/cmListFileLexer.c +++ b/Source/LexerParser/cmListFileLexer.c @@ -2787,7 +2787,7 @@ int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text) /*--------------------------------------------------------------------------*/ cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer) { - if (!lexer->file) { + if (!lexer->file && !lexer->string_buffer) { return 0; } if (cmListFileLexer_yylex(lexer->scanner, lexer)) { @@ -2801,21 +2801,13 @@ cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer) /*--------------------------------------------------------------------------*/ long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer) { - if (lexer->file) { - return lexer->line; - } else { - return 0; - } + return lexer->line; } /*--------------------------------------------------------------------------*/ long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer) { - if (lexer->file) { - return lexer->column; - } else { - return 0; - } + return lexer->column; } /*--------------------------------------------------------------------------*/ diff --git a/Source/LexerParser/cmListFileLexer.in.l b/Source/LexerParser/cmListFileLexer.in.l index fdf14d2..94cf8a5 100644 --- a/Source/LexerParser/cmListFileLexer.in.l +++ b/Source/LexerParser/cmListFileLexer.in.l @@ -500,7 +500,7 @@ int cmListFileLexer_SetString(cmListFileLexer* lexer, const char* text) /*--------------------------------------------------------------------------*/ cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer) { - if (!lexer->file) { + if (!lexer->file && !lexer->string_buffer) { return 0; } if (cmListFileLexer_yylex(lexer->scanner, lexer)) { @@ -514,21 +514,13 @@ cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer) /*--------------------------------------------------------------------------*/ long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer) { - if (lexer->file) { - return lexer->line; - } else { - return 0; - } + return lexer->line; } /*--------------------------------------------------------------------------*/ long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer) { - if (lexer->file) { - return lexer->column; - } else { - return 0; - } + return lexer->column; } /*--------------------------------------------------------------------------*/ diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt index cb89d19..98dd0e2 100644 --- a/Source/QtDialog/CMakeLists.txt +++ b/Source/QtDialog/CMakeLists.txt @@ -178,6 +178,10 @@ if(WIN32) target_sources(cmake-gui PRIVATE $<TARGET_OBJECTS:CMakeVersion>) endif() +if(CMake_JOB_POOL_LINK_BIN) + set_property(TARGET cmake-gui PROPERTY JOB_POOL_LINK "link-bin") +endif() + # cmake-gui has not been updated for `include-what-you-use`. # Block the tool until this is done. set_target_properties(cmake-gui PROPERTIES diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index 436a904..276bf64 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "CMakeSetupDialog.h" +#include <cm/memory> + #include <QCloseEvent> #include <QCoreApplication> #include <QDesktopServices> @@ -39,23 +41,21 @@ QCMakeThread::QCMakeThread(QObject* p) : QThread(p) - , CMakeInstance(nullptr) { } QCMake* QCMakeThread::cmakeInstance() const { - return this->CMakeInstance; + return this->CMakeInstance.get(); } void QCMakeThread::run() { - this->CMakeInstance = new QCMake; + this->CMakeInstance = cm::make_unique<QCMake>(); // emit that this cmake thread is ready for use emit this->cmakeInitialized(); this->exec(); - delete this->CMakeInstance; - this->CMakeInstance = nullptr; + this->CMakeInstance.reset(); } CMakeSetupDialog::CMakeSetupDialog() @@ -1206,7 +1206,7 @@ void CMakeSetupDialog::setSearchFilter(const QString& str) void CMakeSetupDialog::doOutputContextMenu(QPoint pt) { - QMenu* menu = this->Output->createStandardContextMenu(); + std::unique_ptr<QMenu> menu(this->Output->createStandardContextMenu()); menu->addSeparator(); menu->addAction(tr("Find..."), this, SLOT(doOutputFindDialog()), @@ -1220,7 +1220,6 @@ void CMakeSetupDialog::doOutputContextMenu(QPoint pt) QKeySequence(Qt::Key_F8)); menu->exec(this->Output->mapToGlobal(pt)); - delete menu; } void CMakeSetupDialog::doOutputFindDialog() diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h index f23aee6..d1e2035 100644 --- a/Source/QtDialog/CMakeSetupDialog.h +++ b/Source/QtDialog/CMakeSetupDialog.h @@ -3,6 +3,8 @@ #ifndef CMakeSetupDialog_h #define CMakeSetupDialog_h +#include <memory> + #include "QCMake.h" #include <QEventLoop> #include <QMainWindow> @@ -143,7 +145,7 @@ signals: protected: virtual void run(); - QCMake* CMakeInstance; + std::unique_ptr<QCMake> CMakeInstance; }; #endif // CMakeSetupDialog_h diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx index ca28b19..3c24b9b 100644 --- a/Source/QtDialog/FirstConfigure.cxx +++ b/Source/QtDialog/FirstConfigure.cxx @@ -10,8 +10,12 @@ #include "Compilers.h" -StartCompilerSetup::StartCompilerSetup(QWidget* p) +StartCompilerSetup::StartCompilerSetup(QString defaultGeneratorPlatform, + QString defaultGeneratorToolset, + QWidget* p) : QWizardPage(p) + , DefaultGeneratorPlatform(std::move(defaultGeneratorPlatform)) + , DefaultGeneratorToolset(std::move(defaultGeneratorToolset)) { QVBoxLayout* l = new QVBoxLayout(this); l->addWidget(new QLabel(tr("Specify the generator for this project"))); @@ -68,6 +72,10 @@ QFrame* StartCompilerSetup::CreateToolsetWidgets() Toolset = new QLineEdit(frame); l->addWidget(Toolset); + // Default to CMAKE_GENERATOR_TOOLSET env var if set + if (!DefaultGeneratorToolset.isEmpty()) { + this->Toolset->setText(DefaultGeneratorToolset); + } return frame; } @@ -199,6 +207,14 @@ void StartCompilerSetup::onGeneratorChanged(QString const& name) this->PlatformOptions->addItems(platform_list); PlatformFrame->show(); + + // Default to generator platform from environment + if (!DefaultGeneratorPlatform.isEmpty()) { + int platform_index = platforms.indexOf(DefaultGeneratorPlatform); + if (platform_index != -1) { + this->PlatformOptions->setCurrentIndex(platform_index); + } + } } else { PlatformFrame->hide(); } @@ -421,8 +437,26 @@ void ToolchainCompilerSetup::setToolchainFile(const QString& t) FirstConfigure::FirstConfigure() { + const char* env_generator = std::getenv("CMAKE_GENERATOR"); + const char* env_generator_platform = nullptr; + const char* env_generator_toolset = nullptr; + if (env_generator && std::strlen(env_generator)) { + mDefaultGenerator = env_generator; + env_generator_platform = std::getenv("CMAKE_GENERATOR_PLATFORM"); + env_generator_toolset = std::getenv("CMAKE_GENERATOR_TOOLSET"); + } + + if (!env_generator_platform) { + env_generator_platform = ""; + } + + if (!env_generator_toolset) { + env_generator_toolset = ""; + } + // this->setOption(QWizard::HaveFinishButtonOnEarlyPages, true); - this->mStartCompilerSetupPage = new StartCompilerSetup(this); + this->mStartCompilerSetupPage = new StartCompilerSetup( + env_generator_platform, env_generator_toolset, this); this->setPage(Start, this->mStartCompilerSetupPage); QObject::connect(this->mStartCompilerSetupPage, SIGNAL(selectionChanged()), this, SLOT(restart())); @@ -504,6 +538,17 @@ void FirstConfigure::loadFromSettings() this->mCrossCompilerSetupPage->setIncludeMode( settings.value("IncludeMode", 0).toInt()); settings.endGroup(); + + // environment variables take precedence over application settings because... + // - they're harder to set + // - settings always exist after the program is run once, so the environment + // variables would never be used otherwise + // - platform and toolset are populated only from environment variables, so + // this prevents them from being taken from environment, while the + // generator is taken from application settings + if (!mDefaultGenerator.isEmpty()) { + this->mStartCompilerSetupPage->setCurrentGenerator(mDefaultGenerator); + } } void FirstConfigure::saveToSettings() diff --git a/Source/QtDialog/FirstConfigure.h b/Source/QtDialog/FirstConfigure.h index d1db5bf..c26f489 100644 --- a/Source/QtDialog/FirstConfigure.h +++ b/Source/QtDialog/FirstConfigure.h @@ -29,7 +29,8 @@ class StartCompilerSetup : public QWizardPage { Q_OBJECT public: - StartCompilerSetup(QWidget* p); + StartCompilerSetup(QString defaultGeneratorPlatform, + QString defaultGeneratorToolset, QWidget* p); ~StartCompilerSetup(); void setGenerators(std::vector<cmake::GeneratorInfo> const& gens); void setCurrentGenerator(const QString& gen); @@ -64,6 +65,7 @@ protected: QStringList GeneratorsSupportingPlatform; QMultiMap<QString, QString> GeneratorSupportedPlatforms; QMap<QString, QString> GeneratorDefaultPlatform; + QString DefaultGeneratorPlatform, DefaultGeneratorToolset; private: QFrame* CreateToolsetWidgets(); @@ -197,6 +199,7 @@ protected: NativeCompilerSetup* mNativeCompilerSetupPage; CrossCompilerSetup* mCrossCompilerSetupPage; ToolchainCompilerSetup* mToolchainCompilerSetupPage; + QString mDefaultGenerator; }; #endif // FirstConfigure_h diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx index b608fcb..c3e9c84 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -2,10 +2,13 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "QCMake.h" +#include <cm/memory> + #include <QCoreApplication> #include <QDir> #include "cmExternalMakefileProjectGenerator.h" +#include "cmGlobalGenerator.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -34,7 +37,8 @@ QCMake::QCMake(QObject* p) cmSystemTools::SetStderrCallback( [this](std::string const& msg) { this->stderrCallback(msg); }); - this->CMakeInstance = new cmake(cmake::RoleProject, cmState::Project); + this->CMakeInstance = + cm::make_unique<cmake>(cmake::RoleProject, cmState::Project); this->CMakeInstance->SetCMakeEditCommand( cmSystemTools::GetCMakeGUICommand()); this->CMakeInstance->SetProgressCallback( @@ -54,11 +58,7 @@ QCMake::QCMake(QObject* p) } } -QCMake::~QCMake() -{ - delete this->CMakeInstance; - // cmDynamicLoader::FlushCache(); -} +QCMake::~QCMake() = default; void QCMake::loadCache(const QString& dir) { diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h index fa4451b..110a971 100644 --- a/Source/QtDialog/QCMake.h +++ b/Source/QtDialog/QCMake.h @@ -12,6 +12,7 @@ # pragma warning(disable : 4512) #endif +#include <memory> #include <vector> #include <QAtomicInt> @@ -165,7 +166,7 @@ signals: void openPossible(bool possible); protected: - cmake* CMakeInstance; + std::unique_ptr<cmake> CMakeInstance; bool interruptCallback(); void progressCallback(std::string const& msg, float percent); diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx index b85cc33..0b2750d 100644 --- a/Source/bindexplib.cxx +++ b/Source/bindexplib.cxx @@ -64,32 +64,36 @@ */ #include "bindexplib.h" -#include <iostream> +#include <cstddef> #include <sstream> #include <vector> -#include <windows.h> +#ifdef _WIN32 +# include <windows.h> + +# include "cmsys/Encoding.hxx" +#endif -#include "cmsys/Encoding.hxx" #include "cmsys/FStream.hxx" #include "cmSystemTools.h" -#ifndef IMAGE_FILE_MACHINE_ARM -# define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian -#endif +#ifdef _WIN32 +# ifndef IMAGE_FILE_MACHINE_ARM +# define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian +# endif -#ifndef IMAGE_FILE_MACHINE_THUMB -# define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian -#endif +# ifndef IMAGE_FILE_MACHINE_THUMB +# define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian +# endif -#ifndef IMAGE_FILE_MACHINE_ARMNT -# define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian -#endif +# ifndef IMAGE_FILE_MACHINE_ARMNT +# define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian +# endif -#ifndef IMAGE_FILE_MACHINE_ARM64 -# define IMAGE_FILE_MACHINE_ARM64 0xaa64 // ARM64 Little-Endian -#endif +# ifndef IMAGE_FILE_MACHINE_ARM64 +# define IMAGE_FILE_MACHINE_ARM64 0xaa64 // ARM64 Little-Endian +# endif typedef struct cmANON_OBJECT_HEADER_BIGOBJ { @@ -306,6 +310,7 @@ private: SymbolTableType* SymbolTable; bool IsI386; }; +#endif bool DumpFileWithLlvmNm(std::string const& nmPath, const char* filename, std::set<std::string>& symbols, @@ -315,15 +320,15 @@ bool DumpFileWithLlvmNm(std::string const& nmPath, const char* filename, // break up command line into a vector std::vector<std::string> command; command.push_back(nmPath); - command.push_back("--no-weak"); - command.push_back("--defined-only"); - command.push_back("--format=posix"); - command.push_back(filename); + command.emplace_back("--no-weak"); + command.emplace_back("--defined-only"); + command.emplace_back("--format=posix"); + command.emplace_back(filename); // run the command int exit_code = 0; - cmSystemTools::RunSingleCommand(command, &output, &output, &exit_code, "", - cmSystemTools::OUTPUT_NONE); + cmSystemTools::RunSingleCommand(command, &output, &output, &exit_code, + nullptr, cmSystemTools::OUTPUT_NONE); if (exit_code != 0) { fprintf(stderr, "llvm-nm returned an error: %s\n", output.c_str()); @@ -336,7 +341,7 @@ bool DumpFileWithLlvmNm(std::string const& nmPath, const char* filename, if (line.empty()) { // last line continue; } - size_t sym_end = line.find(" "); + size_t sym_end = line.find(' '); if (sym_end == std::string::npos) { fprintf(stderr, "Couldn't parse llvm-nm output line: %s\n", line.c_str()); @@ -366,6 +371,9 @@ bool DumpFile(std::string const& nmPath, const char* filename, std::set<std::string>& symbols, std::set<std::string>& dataSymbols) { +#ifndef _WIN32 + return DumpFileWithLlvmNm(nmPath, filename, symbols, dataSymbols); +#else HANDLE hFile; HANDLE hFileMapping; LPVOID lpFileBase; @@ -446,6 +454,7 @@ bool DumpFile(std::string const& nmPath, const char* filename, CloseHandle(hFileMapping); CloseHandle(hFile); return true; +#endif } bool bindexplib::AddObjectFile(const char* filename) diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 6e04ce5..231a2d6 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -174,7 +174,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, doing = doing_comment; } else if (copy == keyDEPFILE) { doing = doing_depfile; - if (mf.GetGlobalGenerator()->GetName() != "Ninja") { + if (!mf.GetGlobalGenerator()->SupportsCustomCommandDepfile()) { status.SetError("Option DEPFILE not supported by " + mf.GetGlobalGenerator()->GetName()); return false; @@ -215,7 +215,8 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, } if (cmSystemTools::FileIsFullPath(filename)) { - filename = cmSystemTools::CollapseFullPath(filename); + filename = cmSystemTools::CollapseFullPath( + filename, status.GetMakefile().GetHomeOutputDirectory()); } switch (doing) { case doing_depfile: @@ -261,9 +262,9 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, case doing_target: target = copy; break; - case doing_depends: { + case doing_depends: depends.push_back(copy); - } break; + break; case doing_outputs: outputs.push_back(filename); break; @@ -343,7 +344,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, // Target is empty, use the output. mf.AddCustomCommandToOutput( output, byproducts, depends, main_dependency, implicit_depends, - commandLines, comment, working.c_str(), false, escapeOldStyle, + commandLines, comment, working.c_str(), nullptr, false, escapeOldStyle, uses_terminal, command_expand_lists, depfile, job_pool); } else if (!byproducts.empty()) { status.SetError("BYPRODUCTS may not be specified with SOURCE signatures"); diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index e27b126..aa98d89 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -6,7 +6,6 @@ #include "cmCheckCustomOutputs.h" #include "cmCustomCommandLines.h" -#include "cmCustomCommandTypes.h" #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" @@ -215,9 +214,9 @@ bool cmAddCustomTargetCommand(std::vector<std::string> const& args, // Add the utility target to the makefile. bool escapeOldStyle = !verbatim; cmTarget* target = mf.AddUtilityCommand( - targetName, cmCommandOrigin::Project, excludeFromAll, - working_directory.c_str(), byproducts, depends, commandLines, - escapeOldStyle, comment, uses_terminal, command_expand_lists, job_pool); + targetName, excludeFromAll, working_directory.c_str(), byproducts, depends, + commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists, + job_pool); // Add additional user-specified source files to the target. target->AddSources(sources); diff --git a/Source/cmAddDependenciesCommand.cxx b/Source/cmAddDependenciesCommand.cxx index b1fc893..2d55a5a 100644 --- a/Source/cmAddDependenciesCommand.cxx +++ b/Source/cmAddDependenciesCommand.cxx @@ -29,7 +29,7 @@ bool cmAddDependenciesCommand(std::vector<std::string> const& args, // skip over target_name for (std::string const& arg : cmMakeRange(args).advance(1)) { - target->AddUtility(arg, &mf); + target->AddUtility(arg, false, &mf); } } else { mf.IssueMessage( diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index 0439c51..f443fc6 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -2,7 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmAddLibraryCommand.h" -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" @@ -309,7 +310,7 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args, return true; } - cmAppend(srclists, s, args.end()); + cm::append(srclists, s, args.end()); mf.AddLibrary(libName, type, srclists, excludeFromAll); diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx index 6a1a514..35eabaf 100644 --- a/Source/cmAddSubDirectoryCommand.cxx +++ b/Source/cmAddSubDirectoryCommand.cxx @@ -53,7 +53,8 @@ bool cmAddSubDirectoryCommand(std::vector<std::string> const& args, status.SetError(error); return false; } - srcPath = cmSystemTools::CollapseFullPath(srcPath); + srcPath = + cmSystemTools::CollapseFullPath(srcPath, mf.GetHomeOutputDirectory()); // Compute the full path to the binary directory. std::string binPath; diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx index 8942113..205c1c7 100644 --- a/Source/cmAddTestCommand.cxx +++ b/Source/cmAddTestCommand.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmAddTestCommand.h" +#include <cm/memory> + #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" @@ -44,7 +46,7 @@ bool cmAddTestCommand(std::vector<std::string> const& args, } else { test = mf.CreateTest(args[0]); test->SetOldStyle(true); - mf.AddTestGenerator(new cmTestGenerator(test)); + mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test)); } test->SetCommand(command); @@ -141,7 +143,7 @@ bool cmAddTestCommandHandleNameMode(std::vector<std::string> const& args, test->SetProperty("WORKING_DIRECTORY", working_directory.c_str()); } test->SetCommandExpandLists(command_expand_lists); - mf.AddTestGenerator(new cmTestGenerator(test, configurations)); + mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test, configurations)); return true; } diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h index e0d27ee..c0ac551 100644 --- a/Source/cmAlgorithms.h +++ b/Source/cmAlgorithms.h @@ -8,6 +8,7 @@ #include <algorithm> #include <functional> #include <iterator> +#include <memory> #include <unordered_set> #include <utility> #include <vector> @@ -36,12 +37,6 @@ FwdIt cmRotate(FwdIt first, FwdIt middle, FwdIt last) return first; } -template <typename Container, typename Predicate> -void cmEraseIf(Container& cont, Predicate pred) -{ - cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end()); -} - template <typename Range, typename Key> auto cmContainsImpl(Range const& range, Key const& key, cmOverloadPriority<2>) -> decltype(range.exists(key)) @@ -72,40 +67,6 @@ bool cmContains(Range const& range, Key const& key) namespace ContainerAlgorithms { -template <typename T> -struct cmIsPair -{ - enum - { - value = false - }; -}; - -template <typename K, typename V> -struct cmIsPair<std::pair<K, V>> -{ - enum - { - value = true - }; -}; - -template <typename Range, - bool valueTypeIsPair = cmIsPair<typename Range::value_type>::value> -struct DefaultDeleter -{ - void operator()(typename Range::value_type value) const { delete value; } -}; - -template <typename Range> -struct DefaultDeleter<Range, /* valueTypeIsPair = */ true> -{ - void operator()(typename Range::value_type value) const - { - delete value.second; - } -}; - template <typename FwdIt> FwdIt RemoveN(FwdIt i1, FwdIt i2, size_t n) { @@ -138,25 +99,6 @@ using cmBacktraceRange = cmRange<std::vector<cmListFileBacktrace>::const_iterator>; template <typename Range> -void cmDeleteAll(Range const& r) -{ - std::for_each(r.begin(), r.end(), - ContainerAlgorithms::DefaultDeleter<Range>()); -} - -template <typename T, typename Range> -void cmAppend(std::vector<T>& v, Range const& r) -{ - v.insert(v.end(), r.begin(), r.end()); -} - -template <typename T, typename InputIt> -void cmAppend(std::vector<T>& v, InputIt first, InputIt last) -{ - v.insert(v.end(), first, last); -} - -template <typename Range> typename Range::const_iterator cmRemoveN(Range& r, size_t n) { return ContainerAlgorithms::RemoveN(r.begin(), r.end(), n); @@ -197,7 +139,7 @@ template <typename ForwardIterator> ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last) { using Value = typename std::iterator_traits<ForwardIterator>::value_type; - using Hash = struct + struct Hash { std::size_t operator()(ForwardIterator it) const { @@ -205,7 +147,7 @@ ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last) } }; - using Equal = struct + struct Equal { bool operator()(ForwardIterator it1, ForwardIterator it2) const { diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index e5eea79..d29b2ac 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -200,8 +200,11 @@ bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix, bool cmArchiveWrite::AddPath(const char* path, size_t skip, const char* prefix, bool recursive) { - if (!this->AddFile(path, skip, prefix)) { - return false; + if (strcmp(path, ".") != 0 || + (this->Format != "zip" && this->Format != "7zip")) { + if (!this->AddFile(path, skip, prefix)) { + return false; + } } if ((!cmSystemTools::FileIsDirectory(path) || !recursive) || cmSystemTools::FileIsSymlink(path)) { @@ -210,6 +213,9 @@ bool cmArchiveWrite::AddPath(const char* path, size_t skip, const char* prefix, cmsys::Directory d; if (d.Load(path)) { std::string next = cmStrCat(path, '/'); + if (next == "./" && (this->Format == "zip" || this->Format == "7zip")) { + next.clear(); + } std::string::size_type end = next.size(); unsigned long n = d.GetNumberOfFiles(); for (unsigned long i = 0; i < n; ++i) { diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx index 49c9439..b82fb9a 100644 --- a/Source/cmBuildCommand.cxx +++ b/Source/cmBuildCommand.cxx @@ -108,7 +108,7 @@ bool TwoArgsSignature(std::vector<std::string> const& args, if (cacheValue) { return true; } - mf.AddCacheDefinition(define, makecommand.c_str(), + mf.AddCacheDefinition(define, makecommand, "Command used to build entire project " "from the command line.", cmStateEnums::STRING); diff --git a/Source/cmBuildNameCommand.cxx b/Source/cmBuildNameCommand.cxx index 3e517dc..ad4d665 100644 --- a/Source/cmBuildNameCommand.cxx +++ b/Source/cmBuildNameCommand.cxx @@ -28,7 +28,7 @@ bool cmBuildNameCommand(std::vector<std::string> const& args, std::replace(cv.begin(), cv.end(), '/', '_'); std::replace(cv.begin(), cv.end(), '(', '_'); std::replace(cv.begin(), cv.end(), ')', '_'); - mf.AddCacheDefinition(args[0], cv.c_str(), "Name of build.", + mf.AddCacheDefinition(args[0], cv, "Name of build.", cmStateEnums::STRING); } return true; @@ -54,7 +54,7 @@ bool cmBuildNameCommand(std::vector<std::string> const& args, std::replace(buildname.begin(), buildname.end(), '(', '_'); std::replace(buildname.begin(), buildname.end(), ')', '_'); - mf.AddCacheDefinition(args[0], buildname.c_str(), "Name of build.", + mf.AddCacheDefinition(args[0], buildname, "Name of build.", cmStateEnums::STRING); return true; } diff --git a/Source/cmCMakeCommand.cxx b/Source/cmCMakeCommand.cxx new file mode 100644 index 0000000..c11a003 --- /dev/null +++ b/Source/cmCMakeCommand.cxx @@ -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. */ +#include "cmCMakeCommand.h" + +#include <algorithm> +#include <cstddef> + +#include "cmExecutionStatus.h" +#include "cmListFileCache.h" +#include "cmMakefile.h" +#include "cmRange.h" +#include "cmStringAlgorithms.h" + +bool cmCMakeCommand(std::vector<std::string> const& args, + cmExecutionStatus& status) +{ + if (args.empty()) { + status.SetError("called with incorrect number of arguments"); + return false; + } + + cmMakefile& makefile = status.GetMakefile(); + cmListFileContext context = makefile.GetExecutionContext(); + + bool result = false; + + if (args[0] == "INVOKE") { + if (args.size() == 1) { + status.SetError("called with incorrect number of arguments"); + return false; + } + + // First argument is the name of the function to call + cmListFileFunction func; + func.Name = args[1]; + func.Line = context.Line; + + // The rest of the arguments are passed to the function call above + func.Arguments.resize(args.size() - 1); + for (size_t i = 2; i < args.size(); ++i) { + cmListFileArgument lfarg; + lfarg.Line = context.Line; + lfarg.Value = args[i]; + func.Arguments.emplace_back(lfarg); + } + + result = makefile.ExecuteCommand(func, status); + } else if (args[0] == "EVAL") { + if (args.size() < 2) { + status.SetError("called with incorrect number of arguments"); + return false; + } + + auto code_iter = std::find(args.begin(), args.end(), "CODE"); + if (code_iter == args.end()) { + status.SetError("called without CODE argument"); + return false; + } + + const std::string code = cmJoin(cmMakeRange(++code_iter, args.end()), " "); + result = makefile.ReadListFileAsString( + code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL")); + } else { + status.SetError("called with unknown meta-operation"); + } + + return result; +} diff --git a/Source/cmCMakeCommand.h b/Source/cmCMakeCommand.h new file mode 100644 index 0000000..cf9f4c3 --- /dev/null +++ b/Source/cmCMakeCommand.h @@ -0,0 +1,20 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmCMakeCommand_h +#define cmCMakeCommand_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> +#include <vector> + +class cmExecutionStatus; + +/** + * \brief Calls a scripted or build-in command + * + */ +bool cmCMakeCommand(std::vector<std::string> const& args, + cmExecutionStatus& status); + +#endif diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx index 177bca8..f6c1e47 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -221,10 +221,10 @@ void CCONV cmAddUtilityCommand(void* arg, const char* utilityName, // Pass the call to the makefile instance. std::vector<std::string> no_byproducts; - mf->AddUtilityCommand(utilityName, cmCommandOrigin::Project, - (all ? false : true), nullptr, no_byproducts, depends2, - commandLines); + mf->AddUtilityCommand(utilityName, (all ? false : true), nullptr, + no_byproducts, depends2, commandLines); } + void CCONV cmAddCustomCommand(void* arg, const char* source, const char* command, int numArgs, const char** args, int numDepends, @@ -488,24 +488,8 @@ struct cmCPluginAPISourceFile // Keep a map from real cmSourceFile instances stored in a makefile to // the CPluginAPI proxy source file. -class cmCPluginAPISourceFileMap - : public std::map<cmSourceFile*, cmCPluginAPISourceFile*> -{ -public: - using derived = std::map<cmSourceFile*, cmCPluginAPISourceFile*>; - using iterator = derived::iterator; - using value_type = derived::value_type; - cmCPluginAPISourceFileMap() = default; - ~cmCPluginAPISourceFileMap() - { - for (auto const& i : *this) { - delete i.second; - } - } - cmCPluginAPISourceFileMap(const cmCPluginAPISourceFileMap&) = delete; - cmCPluginAPISourceFileMap& operator=(const cmCPluginAPISourceFileMap&) = - delete; -}; +using cmCPluginAPISourceFileMap = + std::map<cmSourceFile*, std::unique_ptr<cmCPluginAPISourceFile>>; cmCPluginAPISourceFileMap cmCPluginAPISourceFiles; void* CCONV cmCreateSourceFile(void) @@ -536,7 +520,7 @@ void CCONV* cmGetSource(void* arg, const char* name) auto i = cmCPluginAPISourceFiles.find(rsf); if (i == cmCPluginAPISourceFiles.end()) { // Create a proxy source file object for this source. - cmCPluginAPISourceFile* sf = new cmCPluginAPISourceFile; + auto sf = cm::make_unique<cmCPluginAPISourceFile>(); sf->RealSourceFile = rsf; sf->FullPath = rsf->ResolveFullPath(); sf->SourceName = @@ -545,10 +529,9 @@ void CCONV* cmGetSource(void* arg, const char* name) cmSystemTools::GetFilenameLastExtension(sf->FullPath); // Store the proxy in the map so it can be re-used and deleted later. - cmCPluginAPISourceFileMap::value_type entry(rsf, sf); - i = cmCPluginAPISourceFiles.insert(entry).first; + i = cmCPluginAPISourceFiles.emplace(rsf, std::move(sf)).first; } - return i->second; + return i->second.get(); } return nullptr; } @@ -569,15 +552,16 @@ void* CCONV cmAddSource(void* arg, void* arg2) } // Create the proxy for the real source file. - cmCPluginAPISourceFile* sf = new cmCPluginAPISourceFile; + auto sf = cm::make_unique<cmCPluginAPISourceFile>(); sf->RealSourceFile = rsf; sf->FullPath = osf->FullPath; sf->SourceName = osf->SourceName; sf->SourceExtension = osf->SourceExtension; // Store the proxy in the map so it can be re-used and deleted later. - cmCPluginAPISourceFiles[rsf] = sf; - return sf; + auto value = sf.get(); + cmCPluginAPISourceFiles[rsf] = std::move(sf); + return value; } const char* CCONV cmSourceFileGetSourceName(void* arg) diff --git a/Source/cmCPluginAPI.h b/Source/cmCPluginAPI.h index 6a95148..19626f0 100644 --- a/Source/cmCPluginAPI.h +++ b/Source/cmCPluginAPI.h @@ -36,7 +36,7 @@ typedef struct of functions are utility functions that are specific to the plugin API =========================================================================*/ /* set/Get the ClientData in the cmLoadedCommandInfo structure, this is how - information is passed from the InitialPass to FInalPass for commands + information is passed from the InitialPass to FinalPass for commands that need a FinalPass and need information from the InitialPass */ void*(CCONV* GetClientData)(void* info); /* return the summed size in characters of all the arguments */ @@ -44,7 +44,7 @@ typedef struct /* free all the memory associated with an argc, argv pair */ void(CCONV* FreeArguments)(int argc, char** argv); /* set/Get the ClientData in the cmLoadedCommandInfo structure, this is how - information is passed from the InitialPass to FInalPass for commands + information is passed from the InitialPass to FinalPass for commands that need a FinalPass and need information from the InitialPass */ void(CCONV* SetClientData)(void* info, void* cd); /* when an error occurs, call this function to set the error string */ diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 6eae26e..fb100b1 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -16,11 +16,15 @@ #include <utility> #include <vector> +#include <cm/memory> +#include <cmext/algorithm> + #include "cmsys/Base64.h" #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" #include "cmsys/Process.h" +#include "cmsys/RegularExpression.hxx" #include "cmsys/SystemInformation.hxx" #include "cm_curl.h" @@ -31,9 +35,6 @@ # include <unistd.h> // IWYU pragma: keep #endif -#include <cm/memory> - -#include "cmAlgorithms.h" #include "cmCTestBuildAndTestHandler.h" #include "cmCTestBuildHandler.h" #include "cmCTestConfigureHandler.h" @@ -83,8 +84,8 @@ struct cmCTest::Private std::string Name; }; - int RepeatTests = 1; // default to run each test once - bool RepeatUntilFail = false; + int RepeatCount = 1; // default to run each test once + cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never; std::string ConfigType; std::string ScheduleType; std::chrono::system_clock::time_point StopTime; @@ -200,13 +201,15 @@ struct cmCTest::Private int SubmitIndex = 0; - cmGeneratedFileStream* OutputLogFile = nullptr; + std::unique_ptr<cmGeneratedFileStream> OutputLogFile; int OutputLogFileLastTag = -1; bool OutputTestOutputOnTestFailure = false; bool OutputColorCode = cmCTest::ColoredOutputSupportedByConsole(); std::map<std::string, std::string> Definitions; + + cmCTest::NoTests NoTestsMode = cmCTest::NoTests::Legacy; }; struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag) @@ -359,10 +362,7 @@ cmCTest::cmCTest() cmSystemTools::EnableVSConsoleOutput(); } -cmCTest::~cmCTest() -{ - delete this->Impl->OutputLogFile; -} +cmCTest::~cmCTest() = default; int cmCTest::GetParallelLevel() const { @@ -1279,7 +1279,7 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output, while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) { processOutput.DecodeText(data, length, strdata); if (output) { - cmAppend(tempOutput, data, data + length); + cm::append(tempOutput, data, data + length); } cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, cmCTestLogWrite(strdata.c_str(), strdata.size())); @@ -1839,11 +1839,16 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, this->SetParallelLevel(plevel); this->Impl->ParallelLevelSetInCli = true; } + if (this->CheckArgument(arg, "--repeat-until-fail")) { if (i >= args.size() - 1) { errormsg = "'--repeat-until-fail' requires an argument"; return false; } + if (this->Impl->RepeatMode != cmCTest::Repeat::Never) { + errormsg = "At most one '--repeat' option may be used."; + return false; + } i++; long repeat = 1; if (!cmStrToLong(args[i], &repeat)) { @@ -1851,9 +1856,42 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, "'--repeat-until-fail' given non-integer value '" + args[i] + "'"; return false; } - this->Impl->RepeatTests = static_cast<int>(repeat); + this->Impl->RepeatCount = static_cast<int>(repeat); if (repeat > 1) { - this->Impl->RepeatUntilFail = true; + this->Impl->RepeatMode = cmCTest::Repeat::UntilFail; + } + } + + if (this->CheckArgument(arg, "--repeat")) { + if (i >= args.size() - 1) { + errormsg = "'--repeat' requires an argument"; + return false; + } + if (this->Impl->RepeatMode != cmCTest::Repeat::Never) { + errormsg = "At most one '--repeat' option may be used."; + return false; + } + i++; + cmsys::RegularExpression repeatRegex( + "^(until-fail|until-pass|after-timeout):([0-9]+)$"); + if (repeatRegex.find(args[i])) { + std::string const& count = repeatRegex.match(2); + unsigned long n = 1; + cmStrToULong(count, &n); // regex guarantees success + this->Impl->RepeatCount = static_cast<int>(n); + if (this->Impl->RepeatCount > 1) { + std::string const& mode = repeatRegex.match(1); + if (mode == "until-fail") { + this->Impl->RepeatMode = cmCTest::Repeat::UntilFail; + } else if (mode == "until-pass") { + this->Impl->RepeatMode = cmCTest::Repeat::UntilPass; + } else if (mode == "after-timeout") { + this->Impl->RepeatMode = cmCTest::Repeat::AfterTimeout; + } + } + } else { + errormsg = "'--repeat' given invalid value '" + args[i] + "'"; + return false; } } @@ -2020,6 +2058,19 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, this->SetNotesFiles(args[i].c_str()); } + const std::string noTestsPrefix = "--no-tests="; + if (cmHasPrefix(arg, noTestsPrefix)) { + const std::string noTestsMode = arg.substr(noTestsPrefix.length()); + if (noTestsMode == "error") { + this->Impl->NoTestsMode = cmCTest::NoTests::Error; + } else if (noTestsMode != "ignore") { + errormsg = "'--no-tests=' given unknown value '" + noTestsMode + "'"; + return false; + } else { + this->Impl->NoTestsMode = cmCTest::NoTests::Ignore; + } + } + // options that control what tests are run if (this->CheckArgument(arg, "-I", "--tests-information") && i < args.size() - 1) { @@ -2204,7 +2255,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output) bool SRArgumentSpecified = false; // copy the command line - cmAppend(this->Impl->InitialCommandLineArguments, args); + cm::append(this->Impl->InitialCommandLineArguments, args); // process the command line arguments for (size_t i = 1; i < args.size(); ++i) { @@ -2847,14 +2898,19 @@ const std::map<std::string, std::string>& cmCTest::GetDefinitions() const return this->Impl->Definitions; } -int cmCTest::GetTestRepeat() const +int cmCTest::GetRepeatCount() const +{ + return this->Impl->RepeatCount; +} + +cmCTest::Repeat cmCTest::GetRepeatMode() const { - return this->Impl->RepeatTests; + return this->Impl->RepeatMode; } -bool cmCTest::GetRepeatUntilFail() const +cmCTest::NoTests cmCTest::GetNoTestsMode() const { - return this->Impl->RepeatUntilFail; + return this->Impl->NoTestsMode; } void cmCTest::SetBuildID(const std::string& id) @@ -2964,10 +3020,10 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args, res = cmsysProcess_WaitForData(cp, &data, &length, nullptr); switch (res) { case cmsysProcess_Pipe_STDOUT: - cmAppend(tempOutput, data, data + length); + cm::append(tempOutput, data, data + length); break; case cmsysProcess_Pipe_STDERR: - cmAppend(tempError, data, data + length); + cm::append(tempError, data, data + length); break; default: done = true; @@ -3027,12 +3083,10 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args, void cmCTest::SetOutputLogFileName(const char* name) { - if (this->Impl->OutputLogFile) { - delete this->Impl->OutputLogFile; - this->Impl->OutputLogFile = nullptr; - } if (name) { - this->Impl->OutputLogFile = new cmGeneratedFileStream(name); + this->Impl->OutputLogFile = cm::make_unique<cmGeneratedFileStream>(name); + } else { + this->Impl->OutputLogFile.reset(); } } diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 82a6f4c..7f8f913 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -431,10 +431,24 @@ public: const std::map<std::string, std::string>& GetDefinitions() const; /** Return the number of times a test should be run */ - int GetTestRepeat() const; + int GetRepeatCount() const; - /** Return true if test should run until fail */ - bool GetRepeatUntilFail() const; + enum class Repeat + { + Never, + UntilFail, + UntilPass, + AfterTimeout, + }; + Repeat GetRepeatMode() const; + + enum class NoTests + { + Legacy, + Error, + Ignore + }; + NoTests GetNoTestsMode() const; void GenerateSubprojectsOutput(cmXMLWriter& xml); std::vector<std::string> GetLabelsForSubprojects(); diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index d627465..dc9aba1 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -190,7 +190,7 @@ bool cmCacheManager::ReadPropertyEntry(std::string const& entryKey, if (entryKey.size() > plen && *(end - plen) == '-' && strcmp(end - plen + 1, *p) == 0) { std::string key = entryKey.substr(0, entryKey.size() - plen); - cmCacheManager::CacheIterator it = this->GetCacheIterator(key.c_str()); + cmCacheManager::CacheIterator it = this->GetCacheIterator(key); if (it.IsAtEnd()) { // Create an entry and store the property. CacheEntry& ne = this->Cache[key]; @@ -497,9 +497,15 @@ cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry( return nullptr; } -cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator(const char* key) +cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator( + const std::string& key) { - return { *this, key }; + return { *this, key.c_str() }; +} + +cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator() +{ + return { *this, nullptr }; } const std::string* cmCacheManager::GetInitializedCacheValue( @@ -617,7 +623,7 @@ const char* cmCacheManager::CacheEntry::GetProperty( const std::string& prop) const { if (prop == "TYPE") { - return cmState::CacheEntryTypeToString(this->Type); + return cmState::CacheEntryTypeToString(this->Type).c_str(); } if (prop == "VALUE") { return this->Value.c_str(); @@ -638,14 +644,15 @@ void cmCacheManager::CacheEntry::SetProperty(const std::string& prop, } void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop, - const char* value, + const std::string& value, bool asString) { if (prop == "TYPE") { - this->Type = cmState::StringToCacheEntryType(value ? value : "STRING"); + this->Type = + cmState::StringToCacheEntryType(!value.empty() ? value : "STRING"); } else if (prop == "VALUE") { - if (value) { - if (!this->Value.empty() && *value && !asString) { + if (!value.empty()) { + if (!this->Value.empty() && !asString) { this->Value += ";"; } this->Value += value; @@ -673,7 +680,7 @@ void cmCacheManager::CacheIterator::SetProperty(const std::string& p, } void cmCacheManager::CacheIterator::AppendProperty(const std::string& p, - const char* v, + const std::string& v, bool asString) { if (!this->IsAtEnd()) { diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h index faa60c5..d8be991 100644 --- a/Source/cmCacheManager.h +++ b/Source/cmCacheManager.h @@ -39,7 +39,7 @@ private: std::vector<std::string> GetPropertyList() const; const char* GetProperty(const std::string&) const; void SetProperty(const std::string& property, const char* value); - void AppendProperty(const std::string& property, const char* value, + void AppendProperty(const std::string& property, const std::string& value, bool asString = false); bool Initialized = false; }; @@ -58,10 +58,10 @@ public: bool GetPropertyAsBool(const std::string&) const; bool PropertyExists(const std::string&) const; void SetProperty(const std::string& property, const char* value); - void AppendProperty(const std::string& property, const char* value, + void AppendProperty(const std::string& property, const std::string& value, bool asString = false); void SetProperty(const std::string& property, bool value); - const char* GetValue() const { return this->GetEntry().Value.c_str(); } + const std::string& GetValue() const { return this->GetEntry().Value; } bool GetValueAsBool() const; void SetValue(const char*); cmStateEnums::CacheEntryType GetType() const @@ -111,7 +111,8 @@ public: void PrintCache(std::ostream&) const; //! Get the iterator for an entry with a given key. - cmCacheManager::CacheIterator GetCacheIterator(const char* key = nullptr); + cmCacheManager::CacheIterator GetCacheIterator(const std::string& key); + cmCacheManager::CacheIterator GetCacheIterator(); //! Remove an entry from the cache void RemoveCacheEntry(const std::string& key); @@ -124,52 +125,52 @@ public: const char* GetCacheEntryValue(const std::string& key) { - cmCacheManager::CacheIterator it = this->GetCacheIterator(key.c_str()); + cmCacheManager::CacheIterator it = this->GetCacheIterator(key); if (it.IsAtEnd()) { return nullptr; } - return it.GetValue(); + return it.GetValue().c_str(); } const char* GetCacheEntryProperty(std::string const& key, std::string const& propName) { - return this->GetCacheIterator(key.c_str()).GetProperty(propName); + return this->GetCacheIterator(key).GetProperty(propName); } cmStateEnums::CacheEntryType GetCacheEntryType(std::string const& key) { - return this->GetCacheIterator(key.c_str()).GetType(); + return this->GetCacheIterator(key).GetType(); } bool GetCacheEntryPropertyAsBool(std::string const& key, std::string const& propName) { - return this->GetCacheIterator(key.c_str()).GetPropertyAsBool(propName); + return this->GetCacheIterator(key).GetPropertyAsBool(propName); } void SetCacheEntryProperty(std::string const& key, std::string const& propName, std::string const& value) { - this->GetCacheIterator(key.c_str()).SetProperty(propName, value.c_str()); + this->GetCacheIterator(key).SetProperty(propName, value.c_str()); } void SetCacheEntryBoolProperty(std::string const& key, std::string const& propName, bool value) { - this->GetCacheIterator(key.c_str()).SetProperty(propName, value); + this->GetCacheIterator(key).SetProperty(propName, value); } void SetCacheEntryValue(std::string const& key, std::string const& value) { - this->GetCacheIterator(key.c_str()).SetValue(value.c_str()); + this->GetCacheIterator(key).SetValue(value.c_str()); } void RemoveCacheEntryProperty(std::string const& key, std::string const& propName) { - this->GetCacheIterator(key.c_str()).SetProperty(propName, nullptr); + this->GetCacheIterator(key).SetProperty(propName, nullptr); } void AppendCacheEntryProperty(std::string const& key, @@ -177,8 +178,7 @@ public: std::string const& value, bool asString = false) { - this->GetCacheIterator(key.c_str()) - .AppendProperty(propName, value.c_str(), asString); + this->GetCacheIterator(key).AppendProperty(propName, value, asString); } std::vector<std::string> GetCacheEntryKeys() diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index 613ae06..379836a 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -5,6 +5,9 @@ #include <cstring> #include <iostream> #include <sstream> +#include <utility> + +#include <cm/memory> #include "cmCommandArgumentLexer.h" #include "cmMakefile.h" @@ -40,10 +43,10 @@ const char* cmCommandArgumentParserHelper::AddString(const std::string& str) if (str.empty()) { return ""; } - char* stVal = new char[str.size() + 1]; - strcpy(stVal, str.c_str()); - this->Variables.push_back(stVal); - return stVal; + auto stVal = cm::make_unique<char[]>(str.size() + 1); + strcpy(stVal.get(), str.c_str()); + this->Variables.push_back(std::move(stVal)); + return this->Variables.back().get(); } const char* cmCommandArgumentParserHelper::ExpandSpecialVariable( @@ -136,11 +139,11 @@ const char* cmCommandArgumentParserHelper::CombineUnions(const char* in1, return in1; } size_t len = strlen(in1) + strlen(in2) + 1; - char* out = new char[len]; - strcpy(out, in1); - strcat(out, in2); - this->Variables.push_back(out); - return out; + auto out = cm::make_unique<char[]>(len); + strcpy(out.get(), in1); + strcat(out.get(), in2); + this->Variables.push_back(std::move(out)); + return this->Variables.back().get(); } void cmCommandArgumentParserHelper::AllocateParserType( @@ -153,11 +156,11 @@ void cmCommandArgumentParserHelper::AllocateParserType( if (len == 0) { return; } - char* out = new char[len + 1]; - memcpy(out, str, len); - out[len] = 0; - pt->str = out; - this->Variables.push_back(out); + auto out = cm::make_unique<char[]>(len + 1); + memcpy(out.get(), str, len); + out.get()[len] = 0; + pt->str = out.get(); + this->Variables.push_back(std::move(out)); } bool cmCommandArgumentParserHelper::HandleEscapeSymbol( @@ -235,10 +238,7 @@ int cmCommandArgumentParserHelper::ParseString(const char* str, int verb) void cmCommandArgumentParserHelper::CleanupParser() { - for (char* var : this->Variables) { - delete[] var; - } - this->Variables.erase(this->Variables.begin(), this->Variables.end()); + this->Variables.clear(); } int cmCommandArgumentParserHelper::LexInput(char* buf, int maxlen) diff --git a/Source/cmCommandArgumentParserHelper.h b/Source/cmCommandArgumentParserHelper.h index 25e6892..b46edcb 100644 --- a/Source/cmCommandArgumentParserHelper.h +++ b/Source/cmCommandArgumentParserHelper.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <memory> #include <string> #include <vector> @@ -69,7 +70,7 @@ private: void CleanupParser(); void SetError(std::string const& msg); - std::vector<char*> Variables; + std::vector<std::unique_ptr<char[]>> Variables; const cmMakefile* Makefile; std::string Result; std::string ErrorString; diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index 6f19697..28b4267 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -91,6 +91,7 @@ # include "cmAddLinkOptionsCommand.h" # include "cmAuxSourceDirectoryCommand.h" # include "cmBuildNameCommand.h" +# include "cmCMakeCommand.h" # include "cmCMakeHostSystemInformationCommand.h" # include "cmExportCommand.h" # include "cmExportLibraryDependenciesCommand.h" @@ -196,8 +197,10 @@ void GetScriptingCommands(cmState* state) "match the opening WHILE command."); #if !defined(CMAKE_BOOTSTRAP) + state->AddBuiltinCommand("cmake_command", cmCMakeCommand); state->AddBuiltinCommand("cmake_host_system_information", cmCMakeHostSystemInformationCommand); + state->AddBuiltinCommand("load_cache", cmLoadCacheCommand); state->AddBuiltinCommand("remove", cmRemoveCommand); state->AddBuiltinCommand("variable_watch", cmVariableWatchCommand); state->AddBuiltinCommand("write_file", cmWriteFileCommand); @@ -279,7 +282,6 @@ void GetProjectCommands(cmState* state) state->AddBuiltinCommand("link_libraries", cmLinkLibrariesCommand); state->AddBuiltinCommand("target_link_directories", cmTargetLinkDirectoriesCommand); - state->AddBuiltinCommand("load_cache", cmLoadCacheCommand); state->AddBuiltinCommand("qt_wrap_cpp", cmQTWrapCPPCommand); state->AddBuiltinCommand("qt_wrap_ui", cmQTWrapUICommand); state->AddBuiltinCommand("remove_definitions", cmRemoveDefinitionsCommand); @@ -339,7 +341,6 @@ void GetProjectCommandsInScriptMode(cmState* state) CM_UNEXPECTED_PROJECT_COMMAND("install"); CM_UNEXPECTED_PROJECT_COMMAND("link_directories"); CM_UNEXPECTED_PROJECT_COMMAND("link_libraries"); - CM_UNEXPECTED_PROJECT_COMMAND("load_cache"); CM_UNEXPECTED_PROJECT_COMMAND("project"); CM_UNEXPECTED_PROJECT_COMMAND("qt_wrap_cpp"); CM_UNEXPECTED_PROJECT_COMMAND("qt_wrap_ui"); diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 19a096b..033cb60 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -17,6 +17,7 @@ #include "cmSourceFile.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" +#include "cmTarget.h" cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt) : GeneratorTarget(gt) @@ -25,27 +26,29 @@ cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt) static_cast<cmLocalCommonGenerator*>(gt->LocalGenerator)) , GlobalCommonGenerator(static_cast<cmGlobalCommonGenerator*>( gt->LocalGenerator->GetGlobalGenerator())) - , ConfigName(LocalCommonGenerator->GetConfigName()) + , ConfigNames(LocalCommonGenerator->GetConfigNames()) { } cmCommonTargetGenerator::~cmCommonTargetGenerator() = default; -std::string const& cmCommonTargetGenerator::GetConfigName() const +std::vector<std::string> const& cmCommonTargetGenerator::GetConfigNames() const { - return this->ConfigName; + return this->ConfigNames; } -const char* cmCommonTargetGenerator::GetFeature(const std::string& feature) +const char* cmCommonTargetGenerator::GetFeature(const std::string& feature, + const std::string& config) { - return this->GeneratorTarget->GetFeature(feature, this->ConfigName); + return this->GeneratorTarget->GetFeature(feature, config); } void cmCommonTargetGenerator::AddModuleDefinitionFlag( - cmLinkLineComputer* linkLineComputer, std::string& flags) + cmLinkLineComputer* linkLineComputer, std::string& flags, + const std::string& config) { cmGeneratorTarget::ModuleDefinitionInfo const* mdi = - this->GeneratorTarget->GetModuleDefinitionInfo(this->GetConfigName()); + this->GeneratorTarget->GetModuleDefinitionInfo(config); if (!mdi || mdi->DefFile.empty()) { return; } @@ -94,57 +97,60 @@ void cmCommonTargetGenerator::AppendFortranFormatFlags( } } -std::string cmCommonTargetGenerator::GetFlags(const std::string& l) +std::string cmCommonTargetGenerator::GetFlags(const std::string& l, + const std::string& config) { - auto i = this->FlagsByLanguage.find(l); - if (i == this->FlagsByLanguage.end()) { + auto i = this->Configs[config].FlagsByLanguage.find(l); + if (i == this->Configs[config].FlagsByLanguage.end()) { std::string flags; - this->LocalCommonGenerator->GetTargetCompileFlags( - this->GeneratorTarget, this->ConfigName, l, flags); + this->LocalCommonGenerator->GetTargetCompileFlags(this->GeneratorTarget, + config, l, flags); ByLanguageMap::value_type entry(l, flags); - i = this->FlagsByLanguage.insert(entry).first; + i = this->Configs[config].FlagsByLanguage.insert(entry).first; } return i->second; } -std::string cmCommonTargetGenerator::GetDefines(const std::string& l) +std::string cmCommonTargetGenerator::GetDefines(const std::string& l, + const std::string& config) { - auto i = this->DefinesByLanguage.find(l); - if (i == this->DefinesByLanguage.end()) { + auto i = this->Configs[config].DefinesByLanguage.find(l); + if (i == this->Configs[config].DefinesByLanguage.end()) { std::set<std::string> defines; - this->LocalCommonGenerator->GetTargetDefines(this->GeneratorTarget, - this->ConfigName, l, defines); + this->LocalCommonGenerator->GetTargetDefines(this->GeneratorTarget, config, + l, defines); std::string definesString; this->LocalCommonGenerator->JoinDefines(defines, definesString, l); ByLanguageMap::value_type entry(l, definesString); - i = this->DefinesByLanguage.insert(entry).first; + i = this->Configs[config].DefinesByLanguage.insert(entry).first; } return i->second; } -std::string cmCommonTargetGenerator::GetIncludes(std::string const& l) +std::string cmCommonTargetGenerator::GetIncludes(std::string const& l, + const std::string& config) { - auto i = this->IncludesByLanguage.find(l); - if (i == this->IncludesByLanguage.end()) { + auto i = this->Configs[config].IncludesByLanguage.find(l); + if (i == this->Configs[config].IncludesByLanguage.end()) { std::string includes; - this->AddIncludeFlags(includes, l); + this->AddIncludeFlags(includes, l, config); ByLanguageMap::value_type entry(l, includes); - i = this->IncludesByLanguage.insert(entry).first; + i = this->Configs[config].IncludesByLanguage.insert(entry).first; } return i->second; } -std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories() - const +std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories( + const std::string& config) const { std::vector<std::string> dirs; std::set<cmGeneratorTarget const*> emitted; if (cmComputeLinkInformation* cli = - this->GeneratorTarget->GetLinkInformation(this->ConfigName)) { + this->GeneratorTarget->GetLinkInformation(config)) { cmComputeLinkInformation::ItemVector const& items = cli->GetItems(); for (auto const& item : items) { cmGeneratorTarget const* linkee = item.Target; @@ -165,19 +171,24 @@ std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories() return dirs; } -std::string cmCommonTargetGenerator::ComputeTargetCompilePDB() const +std::string cmCommonTargetGenerator::ComputeTargetCompilePDB( + const std::string& config) const { std::string compilePdbPath; if (this->GeneratorTarget->GetType() > cmStateEnums::OBJECT_LIBRARY) { return compilePdbPath; } - compilePdbPath = - this->GeneratorTarget->GetCompilePDBPath(this->GetConfigName()); + compilePdbPath = this->GeneratorTarget->GetCompilePDBPath(config); if (compilePdbPath.empty()) { // Match VS default: `$(IntDir)vc$(PlatformToolsetVersion).pdb`. // A trailing slash tells the toolchain to add its default file name. - compilePdbPath = this->GeneratorTarget->GetSupportDirectory() + "/"; + compilePdbPath = this->GeneratorTarget->GetSupportDirectory(); + if (this->GlobalCommonGenerator->IsMultiConfig()) { + compilePdbPath += "/"; + compilePdbPath += config; + } + compilePdbPath += "/"; if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { // Match VS default for static libs: `$(IntDir)$(ProjectName).pdb`. compilePdbPath += this->GeneratorTarget->GetName(); @@ -188,10 +199,10 @@ std::string cmCommonTargetGenerator::ComputeTargetCompilePDB() const return compilePdbPath; } -std::string cmCommonTargetGenerator::GetManifests() +std::string cmCommonTargetGenerator::GetManifests(const std::string& config) { std::vector<cmSourceFile const*> manifest_srcs; - this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName); + this->GeneratorTarget->GetManifests(manifest_srcs, config); std::vector<std::string> manifests; manifests.reserve(manifest_srcs.size()); @@ -206,6 +217,20 @@ std::string cmCommonTargetGenerator::GetManifests() return cmJoin(manifests, " "); } +std::string cmCommonTargetGenerator::GetAIXExports(std::string const&) +{ + std::string aixExports; + if (this->GeneratorTarget->Target->IsAIX()) { + if (const char* exportAll = + this->GeneratorTarget->GetProperty("AIX_EXPORT_ALL_SYMBOLS")) { + if (cmIsOff(exportAll)) { + aixExports = "-n"; + } + } + } + return aixExports; +} + void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags, const std::string& lang, const char* name, bool so) @@ -223,7 +248,10 @@ void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags, int major; int minor; int patch; - this->GeneratorTarget->GetTargetVersion(so, major, minor, patch); + std::string prop = cmStrCat("MACHO_", name, "_VERSION"); + std::string fallback_prop = so ? "SOVERSION" : "VERSION"; + this->GeneratorTarget->GetTargetVersionFallback(prop, fallback_prop, major, + minor, patch); if (major > 0 || minor > 0 || patch > 0) { // Append the flag since a non-zero version is specified. std::ostringstream vflag; diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index 17792d6..b40a2ed 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -25,42 +25,51 @@ public: cmCommonTargetGenerator(cmGeneratorTarget* gt); virtual ~cmCommonTargetGenerator(); - std::string const& GetConfigName() const; + std::vector<std::string> const& GetConfigNames() const; protected: // Feature query methods. - const char* GetFeature(const std::string& feature); + const char* GetFeature(const std::string& feature, + const std::string& config); // Helper to add flag for windows .def file. void AddModuleDefinitionFlag(cmLinkLineComputer* linkLineComputer, - std::string& flags); + std::string& flags, const std::string& config); cmGeneratorTarget* GeneratorTarget; cmMakefile* Makefile; cmLocalCommonGenerator* LocalCommonGenerator; cmGlobalCommonGenerator* GlobalCommonGenerator; - std::string ConfigName; + std::vector<std::string> ConfigNames; void AppendFortranFormatFlags(std::string& flags, cmSourceFile const& source); - virtual void AddIncludeFlags(std::string& flags, - std::string const& lang) = 0; + virtual void AddIncludeFlags(std::string& flags, std::string const& lang, + const std::string& config) = 0; void AppendOSXVerFlag(std::string& flags, const std::string& lang, const char* name, bool so); - using ByLanguageMap = std::map<std::string, std::string>; - std::string GetFlags(const std::string& l); - ByLanguageMap FlagsByLanguage; - std::string GetDefines(const std::string& l); - ByLanguageMap DefinesByLanguage; - std::string GetIncludes(std::string const& l); - ByLanguageMap IncludesByLanguage; - std::string GetManifests(); + std::string GetFlags(const std::string& l, const std::string& config); + std::string GetDefines(const std::string& l, const std::string& config); + std::string GetIncludes(std::string const& l, const std::string& config); + std::string GetManifests(const std::string& config); + std::string GetAIXExports(std::string const& config); + + std::vector<std::string> GetLinkedTargetDirectories( + const std::string& config) const; + std::string ComputeTargetCompilePDB(const std::string& config) const; - std::vector<std::string> GetLinkedTargetDirectories() const; - std::string ComputeTargetCompilePDB() const; +private: + using ByLanguageMap = std::map<std::string, std::string>; + struct ByConfig + { + ByLanguageMap FlagsByLanguage; + ByLanguageMap DefinesByLanguage; + ByLanguageMap IncludesByLanguage; + }; + std::map<std::string, ByConfig> Configs; }; #endif diff --git a/Source/cmComputeComponentGraph.cxx b/Source/cmComputeComponentGraph.cxx index af257ee..81cd878 100644 --- a/Source/cmComputeComponentGraph.cxx +++ b/Source/cmComputeComponentGraph.cxx @@ -123,7 +123,7 @@ void cmComputeComponentGraph::TransferEdges() // We do not attempt to combine duplicate edges, but instead // store the inter-component edges with suitable multiplicity. this->ComponentGraph[i_component].emplace_back( - j_component, ni.IsStrong(), ni.GetBacktrace()); + j_component, ni.IsStrong(), ni.IsCross(), ni.GetBacktrace()); } } } diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index ccef9c8..e9bf5a5 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -412,7 +412,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep) // This shared library dependency must follow the item that listed // it. this->EntryConstraintGraph[dep.DependerIndex].emplace_back( - index, true, cmListFileBacktrace()); + index, true, false, cmListFileBacktrace()); // Target items may have their own dependencies. if (entry.Target) { @@ -514,7 +514,7 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index, // The dependee must come after the depender. if (depender_index >= 0) { this->EntryConstraintGraph[depender_index].emplace_back( - dependee_index, false, cmListFileBacktrace()); + dependee_index, false, false, cmListFileBacktrace()); } else { // This is a direct dependency of the target being linked. this->OriginalEntries.push_back(dependee_index); @@ -587,7 +587,7 @@ void cmComputeLinkDepends::InferDependencies() cmGraphEdgeList& edges = this->EntryConstraintGraph[depender_index]; edges.reserve(edges.size() + common.size()); for (auto const& c : common) { - edges.emplace_back(c, true, cmListFileBacktrace()); + edges.emplace_back(c, true, false, cmListFileBacktrace()); } } } diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 43bfd1d..e806dff 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -7,12 +7,11 @@ #include <map> #include <memory> +#include <queue> #include <set> #include <string> #include <vector> -#include <queue> - #include "cmGraphAdjacencyList.h" #include "cmLinkItem.h" #include "cmListFileCache.h" diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index f3dd840..11570d6 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -8,8 +8,11 @@ #include <sstream> #include <utility> +#include <cm/memory> + #include "cmAlgorithms.h" #include "cmComputeLinkDepends.h" +#include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmListFileCache.h" @@ -256,11 +259,10 @@ cmComputeLinkInformation::cmComputeLinkInformation( "FIND_LIBRARY_USE_OPENBSD_VERSIONING"); // Allocate internals. - this->OrderLinkerSearchPath = new cmOrderDirectories( + this->OrderLinkerSearchPath = cm::make_unique<cmOrderDirectories>( this->GlobalGenerator, target, "linker search path"); - this->OrderRuntimeSearchPath = new cmOrderDirectories( + this->OrderRuntimeSearchPath = cm::make_unique<cmOrderDirectories>( this->GlobalGenerator, target, "runtime search path"); - this->OrderDependentRPath = nullptr; // Get the language used for linking this target. this->LinkLanguage = this->Target->GetLinkerLanguage(config); @@ -358,7 +360,7 @@ cmComputeLinkInformation::cmComputeLinkInformation( this->SharedDependencyMode = SharedDepModeLibDir; } else if (!this->RPathLinkFlag.empty()) { this->SharedDependencyMode = SharedDepModeDir; - this->OrderDependentRPath = new cmOrderDirectories( + this->OrderDependentRPath = cm::make_unique<cmOrderDirectories>( this->GlobalGenerator, target, "dependent library path"); } @@ -400,12 +402,7 @@ cmComputeLinkInformation::cmComputeLinkInformation( "CMAKE_POLICY_WARNING_CMP0060"); } -cmComputeLinkInformation::~cmComputeLinkInformation() -{ - delete this->OrderLinkerSearchPath; - delete this->OrderRuntimeSearchPath; - delete this->OrderDependentRPath; -} +cmComputeLinkInformation::~cmComputeLinkInformation() = default; void cmComputeLinkInformation::AppendValues( std::string& result, std::vector<BT<std::string>>& values) @@ -573,6 +570,15 @@ void cmComputeLinkInformation::AddImplicitLinkInfo() cmGeneratorTarget::LinkClosure const* lc = this->Target->GetLinkClosure(this->Config); for (std::string const& li : lc->Languages) { + + if (li == "CUDA") { + // These need to go before the other implicit link information + // as they could require symbols from those other library + // Currently restricted to CUDA as it is the only language + // we have documented runtime behavior controls for + this->AddRuntimeLinkLibrary(li); + } + // Skip those of the linker language. They are implicit. if (li != this->LinkLanguage) { this->AddImplicitLinkInfo(li); @@ -580,6 +586,39 @@ void cmComputeLinkInformation::AddImplicitLinkInfo() } } +void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang) +{ // Add the lang runtime library flags. This is activated by the presence + // of a default selection whether or not it is overridden by a property. + std::string defaultVar = + cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT"); + const char* langRuntimeLibraryDefault = + this->Makefile->GetDefinition(defaultVar); + if (langRuntimeLibraryDefault && *langRuntimeLibraryDefault) { + const char* runtimeLibraryValue = + this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY")); + if (!runtimeLibraryValue) { + runtimeLibraryValue = langRuntimeLibraryDefault; + } + + std::string runtimeLibrary = + cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate( + runtimeLibraryValue, this->Target->GetLocalGenerator(), this->Config, + this->Target)); + if (!runtimeLibrary.empty()) { + if (const char* runtimeLinkOptions = this->Makefile->GetDefinition( + "CMAKE_" + lang + "_RUNTIME_LIBRARY_LINK_OPTIONS_" + + runtimeLibrary)) { + std::vector<std::string> libsVec = cmExpandedList(runtimeLinkOptions); + for (std::string const& i : libsVec) { + if (!cmContains(this->ImplicitLinkLibs, i)) { + this->AddItem(i, nullptr); + } + } + } + } + } +} + void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang) { // Add libraries for this language that are not implied by the @@ -749,10 +788,10 @@ void cmComputeLinkInformation::AddSharedDepItem(BT<std::string> const& item, if (this->SharedDependencyMode == SharedDepModeLibDir && !this->LinkWithRuntimePath /* AddLibraryRuntimeInfo adds it */) { // Add the item to the linker search path. - order = this->OrderLinkerSearchPath; + order = this->OrderLinkerSearchPath.get(); } else if (this->SharedDependencyMode == SharedDepModeDir) { // Add the item to the separate dependent library search path. - order = this->OrderDependentRPath; + order = this->OrderDependentRPath.get(); } if (order) { if (tgt) { diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index ee74ccd..e50d369 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <memory> #include <set> #include <string> #include <utility> @@ -29,6 +30,9 @@ class cmComputeLinkInformation public: cmComputeLinkInformation(cmGeneratorTarget const* target, const std::string& config); + cmComputeLinkInformation(const cmComputeLinkInformation&) = delete; + cmComputeLinkInformation& operator=(const cmComputeLinkInformation&) = + delete; ~cmComputeLinkInformation(); bool Compute(); @@ -166,7 +170,7 @@ private: cmsys::RegularExpression SplitFramework; // Linker search path computation. - cmOrderDirectories* OrderLinkerSearchPath; + std::unique_ptr<cmOrderDirectories> OrderLinkerSearchPath; bool FinishLinkerSearchDirectories(); void PrintLinkPolicyDiagnosis(std::ostream&); @@ -174,6 +178,7 @@ private: void LoadImplicitLinkInfo(); void AddImplicitLinkInfo(); void AddImplicitLinkInfo(std::string const& lang); + void AddRuntimeLinkLibrary(std::string const& lang); std::set<std::string> ImplicitLinkDirs; std::set<std::string> ImplicitLinkLibs; @@ -186,9 +191,9 @@ private: std::vector<std::string> OldUserFlagItems; std::set<std::string> CMP0060WarnItems; // Dependent library path computation. - cmOrderDirectories* OrderDependentRPath; + std::unique_ptr<cmOrderDirectories> OrderDependentRPath; // Runtime path computation. - cmOrderDirectories* OrderRuntimeSearchPath; + std::unique_ptr<cmOrderDirectories> OrderRuntimeSearchPath; bool OldLinkDirMode; bool OpenBSD; diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 162bab2..41f5346 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -4,6 +4,7 @@ #include <cassert> #include <cstdio> +#include <memory> #include <sstream> #include <utility> @@ -150,6 +151,7 @@ void cmComputeTargetDepends::GetTargetDirectDepends(cmGeneratorTarget const* t, cmGeneratorTarget const* dep = this->Targets[ni]; auto di = deps.insert(dep).first; di->SetType(ni.IsStrong()); + di->SetCross(ni.IsCross()); di->SetBacktrace(ni.GetBacktrace()); } } @@ -157,15 +159,12 @@ void cmComputeTargetDepends::GetTargetDirectDepends(cmGeneratorTarget const* t, void cmComputeTargetDepends::CollectTargets() { // Collect all targets from all generators. - std::vector<cmLocalGenerator*> const& lgens = - this->GlobalGenerator->GetLocalGenerators(); - for (cmLocalGenerator* lgen : lgens) { - const std::vector<cmGeneratorTarget*>& targets = - lgen->GetGeneratorTargets(); - for (cmGeneratorTarget const* ti : targets) { + auto const& lgens = this->GlobalGenerator->GetLocalGenerators(); + for (const auto& lgen : lgens) { + for (const auto& ti : lgen->GetGeneratorTargets()) { int index = static_cast<int>(this->Targets.size()); - this->TargetIndex[ti] = index; - this->Targets.push_back(ti); + this->TargetIndex[ti.get()] = index; + this->Targets.push_back(ti.get()); } } } @@ -199,6 +198,20 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) std::vector<std::string> const& configs = depender->Makefile->GetGeneratorConfigs(); for (std::string const& it : configs) { + cmLinkImplementation const* impl = depender->GetLinkImplementation(it); + + // A target should not depend on itself. + emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace())); + emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace())); + for (cmLinkImplItem const& lib : impl->Libraries) { + // Don't emit the same library twice for this target. + if (emitted.insert(lib).second) { + this->AddTargetDepend(depender_index, lib, true, false); + this->AddInterfaceDepends(depender_index, lib, it, emitted); + } + } + + // Add dependencies on object libraries not otherwise handled above. std::vector<cmSourceFile const*> objectFiles; depender->GetExternalObjects(objectFiles, it); for (cmSourceFile const* o : objectFiles) { @@ -219,22 +232,10 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) return; } const_cast<cmGeneratorTarget*>(depender)->Target->AddUtility( - objLib); + objLib, false); } } } - - cmLinkImplementation const* impl = depender->GetLinkImplementation(it); - - // A target should not depend on itself. - emitted.insert(cmLinkItem(depender, cmListFileBacktrace())); - for (cmLinkImplItem const& lib : impl->Libraries) { - // Don't emit the same library twice for this target. - if (emitted.insert(lib).second) { - this->AddTargetDepend(depender_index, lib, true); - this->AddInterfaceDepends(depender_index, lib, it, emitted); - } - } } } @@ -243,11 +244,12 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) std::set<cmLinkItem> const& tutils = depender->GetUtilityItems(); std::set<cmLinkItem> emitted; // A target should not depend on itself. - emitted.insert(cmLinkItem(depender, cmListFileBacktrace())); + emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace())); + emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace())); for (cmLinkItem const& litem : tutils) { // Don't emit the same utility twice for this target. if (emitted.insert(litem).second) { - this->AddTargetDepend(depender_index, litem, false); + this->AddTargetDepend(depender_index, litem, false, litem.Cross); } } } @@ -269,7 +271,7 @@ void cmComputeTargetDepends::AddInterfaceDepends( // code in the project that caused this dependency to be added. cmLinkItem libBT = lib; libBT.Backtrace = dependee_backtrace; - this->AddTargetDepend(depender_index, libBT, true); + this->AddTargetDepend(depender_index, libBT, true, false); this->AddInterfaceDepends(depender_index, libBT, config, emitted); } } @@ -292,7 +294,8 @@ void cmComputeTargetDepends::AddInterfaceDepends( if (dependee) { // A target should not depend on itself. - emitted.insert(cmLinkItem(depender, cmListFileBacktrace())); + emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace())); + emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace())); this->AddInterfaceDepends(depender_index, dependee, dependee_name.Backtrace, config, emitted); } @@ -300,7 +303,7 @@ void cmComputeTargetDepends::AddInterfaceDepends( void cmComputeTargetDepends::AddTargetDepend(int depender_index, cmLinkItem const& dependee_name, - bool linking) + bool linking, bool cross) { // Get the depender. cmGeneratorTarget const* depender = this->Targets[depender_index]; @@ -345,13 +348,13 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index, if (dependee) { this->AddTargetDepend(depender_index, dependee, dependee_name.Backtrace, - linking); + linking, cross); } } void cmComputeTargetDepends::AddTargetDepend( int depender_index, cmGeneratorTarget const* dependee, - cmListFileBacktrace const& dependee_backtrace, bool linking) + cmListFileBacktrace const& dependee_backtrace, bool linking, bool cross) { if (dependee->IsImported() || dependee->GetType() == cmStateEnums::INTERFACE_LIBRARY) { @@ -361,7 +364,7 @@ void cmComputeTargetDepends::AddTargetDepend( for (cmLinkItem const& i : utils) { if (cmGeneratorTarget const* transitive_dependee = i.Target) { this->AddTargetDepend(depender_index, transitive_dependee, i.Backtrace, - false); + false, i.Cross); } } } else { @@ -373,7 +376,7 @@ void cmComputeTargetDepends::AddTargetDepend( // Add this entry to the dependency graph. this->InitialGraph[depender_index].emplace_back(dependee_index, !linking, - dependee_backtrace); + cross, dependee_backtrace); } } @@ -507,7 +510,8 @@ bool cmComputeTargetDepends::IntraComponent(std::vector<int> const& cmap, for (cmGraphEdge const& edge : el) { int j = edge; if (cmap[j] == c && edge.IsStrong()) { - this->FinalGraph[i].emplace_back(j, true, edge.GetBacktrace()); + this->FinalGraph[i].emplace_back(j, true, edge.IsCross(), + edge.GetBacktrace()); if (!this->IntraComponent(cmap, c, j, head, emitted, visited)) { return false; } @@ -516,7 +520,8 @@ bool cmComputeTargetDepends::IntraComponent(std::vector<int> const& cmap, // Prepend to a linear linked-list of intra-component edges. if (*head >= 0) { - this->FinalGraph[i].emplace_back(*head, false, cmListFileBacktrace()); + this->FinalGraph[i].emplace_back(*head, false, false, + cmListFileBacktrace()); } else { this->ComponentTail[c] = i; } @@ -566,7 +571,8 @@ bool cmComputeTargetDepends::ComputeFinalDepends( int dependee_component = ni; int dependee_component_head = this->ComponentHead[dependee_component]; this->FinalGraph[depender_component_tail].emplace_back( - dependee_component_head, ni.IsStrong(), ni.GetBacktrace()); + dependee_component_head, ni.IsStrong(), ni.IsCross(), + ni.GetBacktrace()); } } return true; diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h index d8060ae..e0d625f 100644 --- a/Source/cmComputeTargetDepends.h +++ b/Source/cmComputeTargetDepends.h @@ -46,10 +46,10 @@ private: void CollectDepends(); void CollectTargetDepends(int depender_index); void AddTargetDepend(int depender_index, cmLinkItem const& dependee_name, - bool linking); + bool linking, bool cross); void AddTargetDepend(int depender_index, cmGeneratorTarget const* dependee, cmListFileBacktrace const& dependee_backtrace, - bool linking); + bool linking, bool cross); bool ComputeFinalDepends(cmComputeComponentGraph const& ccg); void AddInterfaceDepends(int depender_index, cmLinkItem const& dependee_name, const std::string& config, diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 003e60d..fda687f 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -9,6 +9,8 @@ #include <sstream> #include <utility> +#include <cmext/algorithm> + #include "cmsys/RegularExpression.hxx" #include "cmAlgorithms.h" @@ -396,7 +398,7 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs, // copy to the list structure auto argP1 = arg; argP1++; - cmAppend(newArgs2, argP1, argClose); + cm::append(newArgs2, argP1, argClose); newArgs2.pop_back(); // now recursively invoke IsTrue to handle the values inside the // parenthetical expression diff --git a/Source/cmConvertMSBuildXMLToJSON.py b/Source/cmConvertMSBuildXMLToJSON.py index 02074ba..2be3781 100644 --- a/Source/cmConvertMSBuildXMLToJSON.py +++ b/Source/cmConvertMSBuildXMLToJSON.py @@ -35,12 +35,14 @@ def vsflags(*args): return values -def read_msbuild_xml(path, values={}): +def read_msbuild_xml(path, values=None): """Reads the MS Build XML file at the path and returns its contents. Keyword arguments: values -- The map to append the contents to (default {}) """ + if values is None: + values = {} # Attempt to read the file contents try: @@ -76,12 +78,15 @@ def read_msbuild_xml(path, values={}): return values -def read_msbuild_json(path, values=[]): +def read_msbuild_json(path, values=None): """Reads the MS Build JSON file at the path and returns its contents. Keyword arguments: values -- The list to append the contents to (default []) """ + if values is None: + values = [] + if not os.path.exists(path): logging.info('Could not find MS Build JSON file at %s', path) return values diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 5711cae..da04396 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -51,6 +51,8 @@ static std::string const kCMAKE_OSX_ARCHITECTURES = "CMAKE_OSX_ARCHITECTURES"; static std::string const kCMAKE_OSX_DEPLOYMENT_TARGET = "CMAKE_OSX_DEPLOYMENT_TARGET"; static std::string const kCMAKE_OSX_SYSROOT = "CMAKE_OSX_SYSROOT"; +static std::string const kCMAKE_APPLE_ARCH_SYSROOTS = + "CMAKE_APPLE_ARCH_SYSROOTS"; static std::string const kCMAKE_POSITION_INDEPENDENT_CODE = "CMAKE_POSITION_INDEPENDENT_CODE"; static std::string const kCMAKE_SYSROOT = "CMAKE_SYSROOT"; @@ -723,6 +725,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, vars.insert(kCMAKE_OSX_ARCHITECTURES); vars.insert(kCMAKE_OSX_DEPLOYMENT_TARGET); vars.insert(kCMAKE_OSX_SYSROOT); + vars.insert(kCMAKE_APPLE_ARCH_SYSROOTS); vars.insert(kCMAKE_POSITION_INDEPENDENT_CODE); vars.insert(kCMAKE_SYSROOT); vars.insert(kCMAKE_SYSROOT_COMPILE); @@ -1042,7 +1045,9 @@ void cmCoreTryCompile::CleanupFiles(std::string const& binDir) if (deletedFiles.insert(fileName).second) { std::string const fullPath = std::string(binDir).append("/").append(fileName); - if (cmSystemTools::FileIsDirectory(fullPath)) { + if (cmSystemTools::FileIsSymlink(fullPath)) { + cmSystemTools::RemoveFile(fullPath); + } else if (cmSystemTools::FileIsDirectory(fullPath)) { this->CleanupFiles(fullPath); cmSystemTools::RemoveADirectory(fullPath); } else { diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index 09d269b..0dd8722 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -4,27 +4,23 @@ #include <utility> -#include "cmAlgorithms.h" -#include "cmMakefile.h" +#include <cmext/algorithm> -cmCustomCommand::cmCustomCommand(cmMakefile const* mf, - std::vector<std::string> outputs, +cmCustomCommand::cmCustomCommand(std::vector<std::string> outputs, std::vector<std::string> byproducts, std::vector<std::string> depends, cmCustomCommandLines commandLines, - const char* comment, + cmListFileBacktrace lfbt, const char* comment, const char* workingDirectory) : Outputs(std::move(outputs)) , Byproducts(std::move(byproducts)) , Depends(std::move(depends)) , CommandLines(std::move(commandLines)) + , Backtrace(std::move(lfbt)) , Comment(comment ? comment : "") , WorkingDirectory(workingDirectory ? workingDirectory : "") , HaveComment(comment != nullptr) { - if (mf) { - this->Backtrace = mf->GetBacktrace(); - } } const std::vector<std::string>& cmCustomCommand::GetOutputs() const @@ -55,12 +51,12 @@ const char* cmCustomCommand::GetComment() const void cmCustomCommand::AppendCommands(const cmCustomCommandLines& commandLines) { - cmAppend(this->CommandLines, commandLines); + cm::append(this->CommandLines, commandLines); } void cmCustomCommand::AppendDepends(const std::vector<std::string>& depends) { - cmAppend(this->Depends, depends); + cm::append(this->Depends, depends); } bool cmCustomCommand::GetEscapeOldStyle() const @@ -100,7 +96,7 @@ void cmCustomCommand::SetImplicitDepends(cmImplicitDependsList const& l) void cmCustomCommand::AppendImplicitDepends(cmImplicitDependsList const& l) { - cmAppend(this->ImplicitDepends, l); + cm::append(this->ImplicitDepends, l); } bool cmCustomCommand::GetUsesTerminal() const diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index 4689ace..d300fa5 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -12,8 +12,6 @@ #include "cmCustomCommandLines.h" #include "cmListFileCache.h" -class cmMakefile; - class cmImplicitDependsList : public std::vector<std::pair<std::string, std::string>> { @@ -28,11 +26,11 @@ class cmCustomCommand { public: /** Main constructor specifies all information for the command. */ - cmCustomCommand(cmMakefile const* mf, std::vector<std::string> outputs, + cmCustomCommand(std::vector<std::string> outputs, std::vector<std::string> byproducts, std::vector<std::string> depends, - cmCustomCommandLines commandLines, const char* comment, - const char* workingDirectory); + cmCustomCommandLines commandLines, cmListFileBacktrace lfbt, + const char* comment, const char* workingDirectory); /** Get the output file produced by the command. */ const std::vector<std::string>& GetOutputs() const; diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index c1f412d..2432d2b 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -6,7 +6,8 @@ #include <memory> #include <utility> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmGeneratorExpression.h" @@ -29,10 +30,11 @@ void AppendPaths(const std::vector<std::string>& inputs, for (std::string& it : result) { cmSystemTools::ConvertToUnixSlashes(it); if (cmSystemTools::FileIsFullPath(it)) { - it = cmSystemTools::CollapseFullPath(it); + it = cmSystemTools::CollapseFullPath( + it, lg->GetMakefile()->GetHomeOutputDirectory()); } } - cmAppend(output, result); + cm::append(output, result); } } } @@ -56,7 +58,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(clarg); std::string parsed_arg = cge->Evaluate(this->LG, this->Config); if (this->CC.GetCommandExpandLists()) { - cmAppend(argv, cmExpandedList(parsed_arg)); + cm::append(argv, cmExpandedList(parsed_arg)); } else { argv.push_back(std::move(parsed_arg)); } @@ -137,7 +139,7 @@ const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const (target->IsImported() || target->GetProperty("CROSSCOMPILING_EMULATOR") || !this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING"))) { - return target->GetLocation(this->Config); + return target->GetLocation(this->Config).c_str(); } return nullptr; } @@ -201,7 +203,9 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c, if (this->OldStyle) { cmd += escapeForShellOldStyle(emulator[j]); } else { - cmd += this->LG->EscapeForShell(emulator[j], this->MakeVars); + cmd += + this->LG->EscapeForShell(emulator[j], this->MakeVars, false, false, + this->MakeVars && this->LG->IsNinjaMulti()); } } @@ -222,7 +226,9 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c, if (this->OldStyle) { cmd += escapeForShellOldStyle(arg); } else { - cmd += this->LG->EscapeForShell(arg, this->MakeVars); + cmd += + this->LG->EscapeForShell(arg, this->MakeVars, false, false, + this->MakeVars && this->LG->IsNinjaMulti()); } } } diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h index 3bb6e36..868c94a 100644 --- a/Source/cmDependsC.h +++ b/Source/cmDependsC.h @@ -7,12 +7,11 @@ #include <iosfwd> #include <map> +#include <queue> #include <set> #include <string> #include <vector> -#include <queue> - #include "cmsys/RegularExpression.hxx" #include "cmDepends.h" diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index 3692202..983a684 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -102,10 +102,7 @@ cmDependsFortran::cmDependsFortran(cmLocalGenerator* lg) this->SModExt = mf->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT"); } -cmDependsFortran::~cmDependsFortran() -{ - delete this->Internal; -} +cmDependsFortran::~cmDependsFortran() = default; bool cmDependsFortran::WriteDependencies(const std::set<std::string>& sources, const std::string& obj, diff --git a/Source/cmDependsFortran.h b/Source/cmDependsFortran.h index 0485115..e3e0d05 100644 --- a/Source/cmDependsFortran.h +++ b/Source/cmDependsFortran.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <memory> #include <set> #include <string> #include <vector> @@ -84,7 +85,7 @@ protected: std::set<std::string> PPDefinitions; // Internal implementation details. - cmDependsFortranInternals* Internal = nullptr; + std::unique_ptr<cmDependsFortranInternals> Internal; private: std::string MaybeConvertToRelativePath(std::string const& base, diff --git a/Source/cmDependsJavaParserHelper.cxx b/Source/cmDependsJavaParserHelper.cxx index 516bbbf..fc1bbdd 100644 --- a/Source/cmDependsJavaParserHelper.cxx +++ b/Source/cmDependsJavaParserHelper.cxx @@ -8,6 +8,7 @@ #include <iostream> #include <utility> +#include <cm/memory> #include <cm/string_view> #include "cmsys/FStream.hxx" @@ -169,10 +170,11 @@ void cmDependsJavaParserHelper::AllocateParserType( return; } this->UnionsAvailable++; - pt->str = new char[len + 1]; + auto up = cm::make_unique<char[]>(len + 1); + pt->str = up.get(); strncpy(pt->str, str, len); pt->str[len] = 0; - this->Allocates.push_back(pt->str); + this->Allocates.push_back(std::move(up)); } void cmDependsJavaParserHelper::StartClass(const char* cls) @@ -275,10 +277,7 @@ int cmDependsJavaParserHelper::ParseString(const char* str, int verb) void cmDependsJavaParserHelper::CleanupParser() { - for (char* allocate : this->Allocates) { - delete[] allocate; - } - this->Allocates.erase(this->Allocates.begin(), this->Allocates.end()); + this->Allocates.clear(); } int cmDependsJavaParserHelper::LexInput(char* buf, int maxlen) diff --git a/Source/cmDependsJavaParserHelper.h b/Source/cmDependsJavaParserHelper.h index a673b5b..c545ee2 100644 --- a/Source/cmDependsJavaParserHelper.h +++ b/Source/cmDependsJavaParserHelper.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <memory> #include <string> #include <vector> @@ -81,7 +82,7 @@ private: int CurrentDepth; int Verbose; - std::vector<char*> Allocates; + std::vector<std::unique_ptr<char[]>> Allocates; void PrintClasses(); diff --git a/Source/cmDocumentationSection.h b/Source/cmDocumentationSection.h index 15cada6..641263d 100644 --- a/Source/cmDocumentationSection.h +++ b/Source/cmDocumentationSection.h @@ -8,7 +8,8 @@ #include <string> #include <vector> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmDocumentationEntry.h" // Low-level interface for custom documents: @@ -47,7 +48,7 @@ public: } void Append(const std::vector<cmDocumentationEntry>& entries) { - cmAppend(this->Entries, entries); + cm::append(this->Entries, entries); } /** Append an entry to this section using NULL terminated chars */ diff --git a/Source/cmDynamicLoader.cxx b/Source/cmDynamicLoader.cxx index 0b72a94..a3731c1 100644 --- a/Source/cmDynamicLoader.cxx +++ b/Source/cmDynamicLoader.cxx @@ -6,6 +6,7 @@ #include <string> #include <utility> +namespace { class cmDynamicLoaderCache { public: @@ -15,14 +16,15 @@ public: cmsys::DynamicLoader::LibraryHandle& /*p*/); bool FlushCache(const char* path); void FlushCache(); - static cmDynamicLoaderCache* GetInstance(); + static cmDynamicLoaderCache& GetInstance(); private: std::map<std::string, cmsys::DynamicLoader::LibraryHandle> CacheMap; - static cmDynamicLoaderCache* Instance; + static cmDynamicLoaderCache Instance; }; -cmDynamicLoaderCache* cmDynamicLoaderCache::Instance = nullptr; +cmDynamicLoaderCache cmDynamicLoaderCache::Instance; +} cmDynamicLoaderCache::~cmDynamicLoaderCache() = default; @@ -64,15 +66,11 @@ void cmDynamicLoaderCache::FlushCache() for (auto const& it : this->CacheMap) { cmsys::DynamicLoader::CloseLibrary(it.second); } - delete cmDynamicLoaderCache::Instance; - cmDynamicLoaderCache::Instance = nullptr; + this->CacheMap.clear(); } -cmDynamicLoaderCache* cmDynamicLoaderCache::GetInstance() +cmDynamicLoaderCache& cmDynamicLoaderCache::GetInstance() { - if (!cmDynamicLoaderCache::Instance) { - cmDynamicLoaderCache::Instance = new cmDynamicLoaderCache; - } return cmDynamicLoaderCache::Instance; } @@ -80,15 +78,15 @@ cmsys::DynamicLoader::LibraryHandle cmDynamicLoader::OpenLibrary( const char* libname) { cmsys::DynamicLoader::LibraryHandle lh; - if (cmDynamicLoaderCache::GetInstance()->GetCacheFile(libname, lh)) { + if (cmDynamicLoaderCache::GetInstance().GetCacheFile(libname, lh)) { return lh; } lh = cmsys::DynamicLoader::OpenLibrary(libname); - cmDynamicLoaderCache::GetInstance()->CacheFile(libname, lh); + cmDynamicLoaderCache::GetInstance().CacheFile(libname, lh); return lh; } void cmDynamicLoader::FlushCache() { - cmDynamicLoaderCache::GetInstance()->FlushCache(); + cmDynamicLoaderCache::GetInstance().FlushCache(); } diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index 5976b2f..202b205 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -10,13 +10,12 @@ #include <vector> #include <cm/memory> +#include <cmext/algorithm> #include "cmsys/FStream.hxx" #include "cm_kwiml.h" -#include "cmAlgorithms.h" - // Include the ELF format information system header. #if defined(__OpenBSD__) # include <elf_abi.h> @@ -578,7 +577,7 @@ std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries( } char* pdyn = reinterpret_cast<char*>(&dyn); - cmAppend(result, pdyn, pdyn + sizeof(ELF_Dyn)); + cm::append(result, pdyn, pdyn + sizeof(ELF_Dyn)); } return result; diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 80e4bcd..08a0f7e 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -9,11 +9,12 @@ #include <memory> #include <vector> +#include <cmext/algorithm> + #include "cmsys/Process.h" #include "cm_static_string_view.hxx" -#include "cmAlgorithms.h" #include "cmArgumentParser.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" @@ -60,6 +61,8 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, bool ErrorQuiet = false; bool OutputStripTrailingWhitespace = false; bool ErrorStripTrailingWhitespace = false; + bool EchoOutputVariable = false; + bool EchoErrorVariable = false; std::string Encoding; }; @@ -82,7 +85,9 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, &Arguments::OutputStripTrailingWhitespace) .Bind("ERROR_STRIP_TRAILING_WHITESPACE"_s, &Arguments::ErrorStripTrailingWhitespace) - .Bind("ENCODING"_s, &Arguments::Encoding); + .Bind("ENCODING"_s, &Arguments::Encoding) + .Bind("ECHO_OUTPUT_VARIABLE"_s, &Arguments::EchoOutputVariable) + .Bind("ECHO_ERROR_VARIABLE"_s, &Arguments::EchoErrorVariable); std::vector<std::string> unparsedArguments; std::vector<std::string> keywordsMissingValue; @@ -240,28 +245,32 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) { // Put the output in the right place. if (p == cmsysProcess_Pipe_STDOUT && !arguments.OutputQuiet) { - if (arguments.OutputVariable.empty()) { + if (arguments.OutputVariable.empty() || arguments.EchoOutputVariable) { processOutput.DecodeText(data, length, strdata, 1); cmSystemTools::Stdout(strdata); - } else { + } + if (!arguments.OutputVariable.empty()) { cmExecuteProcessCommandAppend(tempOutput, data, length); } } else if (p == cmsysProcess_Pipe_STDERR && !arguments.ErrorQuiet) { - if (arguments.ErrorVariable.empty()) { + if (arguments.ErrorVariable.empty() || arguments.EchoErrorVariable) { processOutput.DecodeText(data, length, strdata, 2); cmSystemTools::Stderr(strdata); - } else { + } + if (!arguments.ErrorVariable.empty()) { cmExecuteProcessCommandAppend(tempError, data, length); } } } - if (!arguments.OutputQuiet && arguments.OutputVariable.empty()) { + if (!arguments.OutputQuiet && + (arguments.OutputVariable.empty() || arguments.EchoOutputVariable)) { processOutput.DecodeText(std::string(), strdata, 1); if (!strdata.empty()) { cmSystemTools::Stdout(strdata); } } - if (!arguments.ErrorQuiet && arguments.ErrorVariable.empty()) { + if (!arguments.ErrorQuiet && + (arguments.ErrorVariable.empty() || arguments.EchoErrorVariable)) { processOutput.DecodeText(std::string(), strdata, 2); if (!strdata.empty()) { cmSystemTools::Stderr(strdata); @@ -402,6 +411,6 @@ void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data, --length; } #endif - cmAppend(output, data, data + length); + cm::append(output, data, data + length); } } diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 7e9a987..d22bd48 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -8,6 +8,7 @@ #include <sstream> #include <utility> +#include "cmAlgorithms.h" #include "cmExportSet.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" @@ -300,11 +301,10 @@ cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg, std::vector<std::string> exportFiles; std::string ns; - std::map<std::string, cmExportBuildFileGenerator*>& exportSets = - gg->GetBuildExportSets(); + auto& exportSets = gg->GetBuildExportSets(); for (auto const& exp : exportSets) { - const cmExportBuildFileGenerator* exportSet = exp.second; + const auto& exportSet = exp.second; std::vector<std::string> targets; exportSet->GetTargets(targets); if (cmContains(targets, name)) { diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 11fbd02..66e8cbb 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -10,7 +10,8 @@ #include <utility> #include <vector> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmExportFileGenerator.h" #include "cmStateTypes.h" @@ -41,7 +42,7 @@ public: void GetTargets(std::vector<std::string>& targets) const; void AppendTargets(std::vector<std::string> const& targets) { - cmAppend(this->Targets, targets); + cm::append(this->Targets, targets); } void SetExportSet(cmExportSet*); diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 2a6bf5d..b7cc193 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -6,6 +6,8 @@ #include <sstream> #include <utility> +#include <cm/memory> + #include "cmsys/RegularExpression.hxx" #include "cm_static_string_view.hxx" @@ -182,11 +184,11 @@ bool cmExportCommand(std::vector<std::string> const& args, } // Setup export file generation. - cmExportBuildFileGenerator* ebfg = nullptr; + std::unique_ptr<cmExportBuildFileGenerator> ebfg = nullptr; if (android) { - ebfg = new cmExportBuildAndroidMKGenerator; + ebfg = cm::make_unique<cmExportBuildAndroidMKGenerator>(); } else { - ebfg = new cmExportBuildFileGenerator; + ebfg = cm::make_unique<cmExportBuildFileGenerator>(); } ebfg->SetExportFile(fname.c_str()); ebfg->SetNamespace(arguments.Namespace); @@ -196,7 +198,7 @@ bool cmExportCommand(std::vector<std::string> const& args, } else { ebfg->SetTargets(targets); } - mf.AddExportBuildFileGenerator(ebfg); + mf.AddExportBuildFileGenerator(ebfg.get()); ebfg->SetExportOld(arguments.ExportOld); // Compute the set of configurations exported. @@ -209,9 +211,9 @@ bool cmExportCommand(std::vector<std::string> const& args, ebfg->AddConfiguration(ct); } if (exportSet != nullptr) { - gg->AddBuildExportExportSet(ebfg); + gg->AddBuildExportExportSet(std::move(ebfg)); } else { - gg->AddBuildExportSet(ebfg); + gg->AddBuildExportSet(std::move(ebfg)); } return true; diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index aeef602..6441e6f 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -14,6 +14,7 @@ #include "cmComputeLinkInformation.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" #include "cmLinkItem.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -60,9 +61,9 @@ void cmExportFileGenerator::SetExportFile(const char* mainFile) cmSystemTools::GetFilenameLastExtension(this->MainImportFile); } -const char* cmExportFileGenerator::GetMainExportFileName() const +const std::string& cmExportFileGenerator::GetMainExportFileName() const { - return this->MainImportFile.c_str(); + return this->MainImportFile; } bool cmExportFileGenerator::GenerateImportFile() @@ -640,6 +641,9 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( std::string sep; input.clear(); for (std::string& li : parts) { + if (cmHasLiteralPrefix(li, CMAKE_DIRECTORY_ID_SEP)) { + continue; + } if (cmGeneratorExpression::Find(li) == std::string::npos) { this->AddTargetNamespace(li, target, missingTargets); } else { @@ -1062,6 +1066,12 @@ void cmExportFileGenerator::GenerateImportTargetCode( if (target->IsCFBundleOnApple()) { os << "set_property(TARGET " << targetName << " PROPERTY BUNDLE 1)\n"; } + + // generate DEPRECATION + if (target->IsDeprecated()) { + os << "set_property(TARGET " << targetName << " PROPERTY DEPRECATION " + << cmExportFileGeneratorEscape(target->GetDeprecation()) << ")\n"; + } os << "\n"; } diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 0d69779..e9d0da7 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -46,7 +46,7 @@ public: /** Set the full path to the export file to generate. */ void SetExportFile(const char* mainFile); - const char* GetMainExportFileName() const; + const std::string& GetMainExportFileName() const; /** Set the namespace in which to place exported target names. */ void SetNamespace(const std::string& ns) { this->Namespace = ns; } diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx index 2d732c1..9702e0e 100644 --- a/Source/cmExportInstallAndroidMKGenerator.cxx +++ b/Source/cmExportInstallAndroidMKGenerator.cxx @@ -49,7 +49,7 @@ void cmExportInstallAndroidMKGenerator::GenerateImportHeaderCode( if (te->ArchiveGenerator) { dest = te->ArchiveGenerator->GetDestination(""); } - te->Target->Target->SetProperty("__dest", dest.c_str()); + te->Target->Target->SetProperty("__dest", dest); } } diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 6d29c99..987ec9e 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -258,15 +258,7 @@ void cmExportInstallFileGenerator::LoadConfigFiles(std::ostream& os) void cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string& input) { - std::string::size_type pos = 0; - std::string::size_type lastPos = pos; - - while ((pos = input.find("$<INSTALL_PREFIX>", lastPos)) != - std::string::npos) { - std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1; - input.replace(pos, endPos - pos, "${_IMPORT_PREFIX}"); - lastPos = endPos; - } + cmGeneratorExpression::ReplaceInstallPrefix(input, "${_IMPORT_PREFIX}"); } bool cmExportInstallFileGenerator::GenerateImportFileConfig( @@ -525,13 +517,14 @@ void cmExportInstallFileGenerator::ComplainAboutMissingTarget( } std::string cmExportInstallFileGenerator::InstallNameDir( - cmGeneratorTarget* target, const std::string& /*config*/) + cmGeneratorTarget* target, const std::string& config) { std::string install_name_dir; cmMakefile* mf = target->Target->GetMakefile(); if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { - install_name_dir = target->GetInstallNameDirForInstallTree(); + install_name_dir = + target->GetInstallNameDirForInstallTree(config, "${_IMPORT_PREFIX}"); } return install_name_dir; diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx index 89093e9..6011ba4 100644 --- a/Source/cmExportLibraryDependenciesCommand.cxx +++ b/Source/cmExportLibraryDependenciesCommand.cxx @@ -12,6 +12,7 @@ #include "cmExecutionStatus.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -20,6 +21,8 @@ #include "cmTargetLinkLibraryType.h" #include "cmake.h" +class cmListFileBacktrace; + static void FinalAction(cmMakefile& makefile, std::string const& filename, bool append) { @@ -46,11 +49,11 @@ static void FinalAction(cmMakefile& makefile, std::string const& filename, // the project. cmake* cm = makefile.GetCMakeInstance(); cmGlobalGenerator* global = cm->GetGlobalGenerator(); - const std::vector<cmMakefile*>& locals = global->GetMakefiles(); + const auto& locals = global->GetMakefiles(); std::map<std::string, std::string> libDepsOld; std::map<std::string, std::string> libDepsNew; std::map<std::string, std::string> libTypes; - for (cmMakefile* local : locals) { + for (const auto& local : locals) { for (auto const& tgt : local->GetTargets()) { // Get the current target. cmTarget const& target = tgt.second; @@ -150,9 +153,9 @@ bool cmExportLibraryDependenciesCommand(std::vector<std::string> const& args, std::string const& filename = args[0]; bool const append = args.size() > 1 && args[1] == "APPEND"; - status.GetMakefile().AddFinalAction( - [filename, append](cmMakefile& makefile) { - FinalAction(makefile, filename, append); + status.GetMakefile().AddGeneratorAction( + [filename, append](cmLocalGenerator& lg, const cmListFileBacktrace&) { + FinalAction(*lg.GetMakefile(), filename, append); }); return true; diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index fafa51b..3df6a5c 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -70,7 +70,8 @@ std::string cmExportTryCompileFileGenerator::FindTargets( std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop); cmTarget dummyHead("try_compile_dummy_exe", cmStateEnums::EXECUTABLE, - cmTarget::VisibilityNormal, tgt->Target->GetMakefile()); + cmTarget::VisibilityNormal, tgt->Target->GetMakefile(), + true); cmGeneratorTarget gDummyHead(&dummyHead, tgt->GetLocalGenerator()); diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h index a472a06..2b8d505 100644 --- a/Source/cmExternalMakefileProjectGenerator.h +++ b/Source/cmExternalMakefileProjectGenerator.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <memory> #include <string> #include <vector> @@ -78,7 +79,7 @@ public: std::vector<std::string> GetSupportedGlobalGenerators() const; std::vector<std::string> Aliases; - virtual cmExternalMakefileProjectGenerator* + virtual std::unique_ptr<cmExternalMakefileProjectGenerator> CreateExternalMakefileProjectGenerator() const = 0; void AddSupportedGlobalGenerator(const std::string& base); @@ -100,10 +101,10 @@ public: { } - cmExternalMakefileProjectGenerator* CreateExternalMakefileProjectGenerator() - const override + std::unique_ptr<cmExternalMakefileProjectGenerator> + CreateExternalMakefileProjectGenerator() const override { - T* p = new T; + std::unique_ptr<cmExternalMakefileProjectGenerator> p(new T); p->SetName(GetName()); return p; } diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index 5a5d959..b710467 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -3,10 +3,13 @@ #include "cmExtraCodeBlocksGenerator.h" #include <map> +#include <memory> #include <ostream> #include <set> #include <utility> +#include <cmext/algorithm> + #include "cmAlgorithms.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" @@ -209,7 +212,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( // Collect all files std::vector<std::string> listFiles; for (cmLocalGenerator* lg : it.second) { - cmAppend(listFiles, lg->GetMakefile()->GetListFiles()); + cm::append(listFiles, lg->GetMakefile()->GetListFiles()); } // Convert @@ -283,8 +286,8 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( // add all executable and library targets and some of the GLOBAL // and UTILITY targets for (cmLocalGenerator* lg : lgs) { - const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { + const auto& targets = lg->GetGeneratorTargets(); + for (const auto& target : targets) { std::string targetName = target->GetName(); switch (target->GetType()) { case cmStateEnums::GLOBAL_TARGET: { @@ -315,7 +318,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( case cmStateEnums::SHARED_LIBRARY: case cmStateEnums::MODULE_LIBRARY: case cmStateEnums::OBJECT_LIBRARY: { - cmGeneratorTarget* gt = target; + cmGeneratorTarget* gt = target.get(); this->AppendTarget(xml, targetName, gt, make, lg, compiler, makeArgs); std::string fastTarget = cmStrCat(targetName, "/fast"); @@ -341,8 +344,8 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( for (cmLocalGenerator* lg : lgs) { cmMakefile* makefile = lg->GetMakefile(); - const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { + const auto& targets = lg->GetGeneratorTargets(); + for (const auto& target : targets) { switch (target->GetType()) { case cmStateEnums::EXECUTABLE: case cmStateEnums::STATIC_LIBRARY: @@ -352,13 +355,12 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( case cmStateEnums::UTILITY: // can have sources since 2.6.3 { std::vector<cmSourceFile*> sources; - cmGeneratorTarget* gt = target; - gt->GetSourceFiles(sources, - makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); + target->GetSourceFiles( + sources, makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); for (cmSourceFile* s : sources) { // don't add source files from UTILITY target which have the // GENERATED property set: - if (gt->GetType() == cmStateEnums::UTILITY && + if (target->GetType() == cmStateEnums::UTILITY && s->GetIsGenerated()) { continue; } @@ -391,7 +393,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( } CbpUnit& cbpUnit = allFiles[fullPath]; - cbpUnit.Targets.push_back(target); + cbpUnit.Targets.push_back(target.get()); } } default: // intended fallthrough @@ -558,19 +560,19 @@ void cmExtraCodeBlocksGenerator::AppendTarget( { std::vector<std::string> includes; lg->GetIncludeDirectories(includes, target, "C", buildType); - cmAppend(allIncludeDirs, includes); + cm::append(allIncludeDirs, includes); } std::string systemIncludeDirs = makefile->GetSafeDefinition( "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS"); if (!systemIncludeDirs.empty()) { - cmAppend(allIncludeDirs, cmExpandedList(systemIncludeDirs)); + cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs)); } systemIncludeDirs = makefile->GetSafeDefinition( "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS"); if (!systemIncludeDirs.empty()) { - cmAppend(allIncludeDirs, cmExpandedList(systemIncludeDirs)); + cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs)); } auto end = cmRemoveDuplicates(allIncludeDirs); diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index c7b7457..de40c77 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -4,6 +4,7 @@ #include <cstring> #include <map> +#include <memory> #include <set> #include <sstream> #include <utility> @@ -116,10 +117,9 @@ std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByTarget( { std::vector<std::string> retval; // for each target in the workspace create a codelite project - const std::vector<cmLocalGenerator*>& lgs = - this->GlobalGenerator->GetLocalGenerators(); - for (cmLocalGenerator* lg : lgs) { - for (cmGeneratorTarget* lt : lg->GetGeneratorTargets()) { + const auto& lgs = this->GlobalGenerator->GetLocalGenerators(); + for (const auto& lg : lgs) { + for (const auto& lt : lg->GetGeneratorTargets()) { cmStateEnums::TargetType type = lt->GetType(); std::string const& outputDir = lg->GetCurrentBinaryDirectory(); std::string targetName = lt->GetName(); @@ -142,7 +142,7 @@ std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByTarget( xml->Attribute("Active", "No"); xml->EndElement(); - CreateNewProjectFile(lt, filename); + CreateNewProjectFile(lt.get(), filename); break; default: break; @@ -269,9 +269,9 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile( for (cmLocalGenerator* lg : lgs) { cmMakefile* makefile = lg->GetMakefile(); - const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { - projectType = CollectSourceFiles(makefile, target, cFiles, otherFiles); + for (const auto& target : lg->GetGeneratorTargets()) { + projectType = + CollectSourceFiles(makefile, target.get(), cFiles, otherFiles); } } @@ -634,7 +634,10 @@ std::string cmExtraCodeLiteGenerator::GetBuildCommand( if (generator == "NMake Makefiles" || generator == "Ninja") { ss << make; } else if (generator == "MinGW Makefiles" || generator == "Unix Makefiles") { - ss << make << " -f$(ProjectPath)/Makefile -j " << this->CpuCount; + ss << make << " -f$(ProjectPath)/Makefile"; + if (this->CpuCount > 0) { + ss << " -j " << this->CpuCount; + } } if (!targetName.empty()) { ss << " " << targetName; diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index b286acf..8ab30c0 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -6,6 +6,7 @@ #include <cassert> #include <cstdio> #include <map> +#include <memory> #include <sstream> #include <utility> @@ -98,7 +99,7 @@ void cmExtraEclipseCDT4Generator::EnableLanguage( void cmExtraEclipseCDT4Generator::Generate() { - cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0]; + const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0]; const cmMakefile* mf = lg->GetMakefile(); std::string eclipseVersion = mf->GetSafeDefinition("CMAKE_ECLIPSE_VERSION"); @@ -175,7 +176,7 @@ void cmExtraEclipseCDT4Generator::Generate() void cmExtraEclipseCDT4Generator::CreateSettingsResourcePrefsFile() { - cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0]; + const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0]; cmMakefile* mf = lg->GetMakefile(); const std::string filename = @@ -198,7 +199,7 @@ void cmExtraEclipseCDT4Generator::CreateSourceProjectFile() assert(this->HomeDirectory != this->HomeOutputDirectory); // set up the project name: <project>-Source@<baseSourcePathName> - cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0]; + const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0]; std::string name = cmExtraEclipseCDT4Generator::GenerateProjectName( lg->GetProjectName(), "Source", cmExtraEclipseCDT4Generator::GetPathBasename(this->HomeDirectory)); @@ -231,9 +232,9 @@ void cmExtraEclipseCDT4Generator::CreateSourceProjectFile() void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out, const char* envVar, - cmLocalGenerator* lg) + cmLocalGenerator& lg) { - cmMakefile* mf = lg->GetMakefile(); + cmMakefile* mf = lg.GetMakefile(); // get the variables from the environment and from the cache and then // figure out which one to use: @@ -243,7 +244,7 @@ void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out, std::string cacheEntryName = cmStrCat("CMAKE_ECLIPSE_ENVVAR_", envVar); const std::string* cacheValue = - lg->GetState()->GetInitializedCacheValue(cacheEntryName); + lg.GetState()->GetInitializedCacheValue(cacheEntryName); // now we have both, decide which one to use std::string valueToUse; @@ -254,9 +255,9 @@ void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out, // The variable is in the env, but not in the cache. Use it and put it // in the cache valueToUse = envVarValue; - mf->AddCacheDefinition(cacheEntryName, valueToUse.c_str(), - cacheEntryName.c_str(), cmStateEnums::STRING, true); - mf->GetCMakeInstance()->SaveCache(lg->GetBinaryDirectory()); + mf->AddCacheDefinition(cacheEntryName, valueToUse, cacheEntryName.c_str(), + cmStateEnums::STRING, true); + mf->GetCMakeInstance()->SaveCache(lg.GetBinaryDirectory()); } else if (!envVarSet && cacheValue != nullptr) { // It is already in the cache, but not in the env, so use it from the cache valueToUse = *cacheValue; @@ -269,10 +270,10 @@ void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out, valueToUse = *cacheValue; if (valueToUse.find(envVarValue) == std::string::npos) { valueToUse = envVarValue; - mf->AddCacheDefinition(cacheEntryName, valueToUse.c_str(), + mf->AddCacheDefinition(cacheEntryName, valueToUse, cacheEntryName.c_str(), cmStateEnums::STRING, true); - mf->GetCMakeInstance()->SaveCache(lg->GetBinaryDirectory()); + mf->GetCMakeInstance()->SaveCache(lg.GetBinaryDirectory()); } } @@ -283,7 +284,7 @@ void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out, void cmExtraEclipseCDT4Generator::CreateProjectFile() { - cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0]; + const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0]; cmMakefile* mf = lg->GetMakefile(); const std::string filename = this->HomeOutputDirectory + "/.project"; @@ -350,15 +351,15 @@ void cmExtraEclipseCDT4Generator::CreateProjectFile() // set vsvars32.bat environment available at CMake time, // but not necessarily when eclipse is open if (compilerId == "MSVC") { - AddEnvVar(environment, "PATH", lg); - AddEnvVar(environment, "INCLUDE", lg); - AddEnvVar(environment, "LIB", lg); - AddEnvVar(environment, "LIBPATH", lg); + AddEnvVar(environment, "PATH", *lg); + AddEnvVar(environment, "INCLUDE", *lg); + AddEnvVar(environment, "LIB", *lg); + AddEnvVar(environment, "LIBPATH", *lg); } else if (compilerId == "Intel") { // if the env.var is set, use this one and put it in the cache // if the env.var is not set, but the value is in the cache, // use it from the cache: - AddEnvVar(environment, "INTEL_LICENSE_FILE", lg); + AddEnvVar(environment, "INTEL_LICENSE_FILE", *lg); } AppendDictionary(xml, "org.eclipse.cdt.make.core.environment", environment.str()); @@ -494,11 +495,11 @@ void cmExtraEclipseCDT4Generator::CreateLinksForTargets(cmXMLWriter& xml) cmExtraEclipseCDT4Generator::AppendLinkedResource( xml, linkName, "virtual:/virtual", VirtualFolder); - for (cmLocalGenerator* lg : this->GlobalGenerator->GetLocalGenerators()) { + for (const auto& lg : this->GlobalGenerator->GetLocalGenerators()) { cmMakefile* makefile = lg->GetMakefile(); - const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); + const auto& targets = lg->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { + for (const auto& target : targets) { std::string linkName2 = cmStrCat(linkName, '/'); switch (target->GetType()) { case cmStateEnums::EXECUTABLE: @@ -519,10 +520,9 @@ void cmExtraEclipseCDT4Generator::CreateLinksForTargets(cmXMLWriter& xml) std::vector<cmSourceGroup> sourceGroups = makefile->GetSourceGroups(); // get the files from the source lists then add them to the groups - cmGeneratorTarget* gt = const_cast<cmGeneratorTarget*>(target); std::vector<cmSourceFile*> files; - gt->GetSourceFiles(files, - makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); + target->GetSourceFiles( + files, makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); for (cmSourceFile* sf : files) { // Add the file to the list of sources. std::string const& source = sf->ResolveFullPath(); @@ -606,7 +606,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const { std::set<std::string> emmited; - cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0]; + const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0]; const cmMakefile* mf = lg->GetMakefile(); const std::string filename = this->HomeOutputDirectory + "/.cproject"; @@ -752,7 +752,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const // add pre-processor definitions to allow eclipse to gray out sections emmited.clear(); - for (cmLocalGenerator* lgen : this->GlobalGenerator->GetLocalGenerators()) { + for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) { if (const char* cdefs = lgen->GetMakefile()->GetProperty("COMPILE_DEFINITIONS")) { @@ -859,16 +859,15 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const // include dirs emmited.clear(); - for (cmLocalGenerator* lgen : this->GlobalGenerator->GetLocalGenerators()) { - const std::vector<cmGeneratorTarget*>& targets = - lgen->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { + for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) { + const auto& targets = lgen->GetGeneratorTargets(); + for (const auto& target : targets) { if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } std::vector<std::string> includeDirs; std::string config = mf->GetSafeDefinition("CMAKE_BUILD_TYPE"); - lgen->GetIncludeDirectories(includeDirs, target, "C", config); + lgen->GetIncludeDirectories(includeDirs, target.get(), "C", config); this->AppendIncludeDirectories(xml, includeDirs, emmited); } } @@ -915,16 +914,15 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const // add all executable and library targets and some of the GLOBAL // and UTILITY targets - for (cmLocalGenerator* lgen : this->GlobalGenerator->GetLocalGenerators()) { - const std::vector<cmGeneratorTarget*>& targets = - lgen->GetGeneratorTargets(); + for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) { + const auto& targets = lgen->GetGeneratorTargets(); std::string subdir = lgen->MaybeConvertToRelativePath( this->HomeOutputDirectory, lgen->GetCurrentBinaryDirectory()); if (subdir == ".") { subdir.clear(); } - for (cmGeneratorTarget* target : targets) { + for (const auto& target : targets) { std::string targetName = target->GetName(); switch (target->GetType()) { case cmStateEnums::GLOBAL_TARGET: { @@ -975,8 +973,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const std::string cleanArgs = cmStrCat("-E chdir \"", lgen->GetCurrentBinaryDirectory(), "\" \"", cmSystemTools::GetCMakeCommand(), "\" -P \""); - cmGeneratorTarget* gt = target; - cleanArgs += lgen->GetTargetDirectory(gt); + cleanArgs += lgen->GetTargetDirectory(target.get()); cleanArgs += "/cmake_clean.cmake\""; cmExtraEclipseCDT4Generator::AppendTarget( xml, "Clean", cmSystemTools::GetCMakeCommand(), cleanArgs, diff --git a/Source/cmExtraEclipseCDT4Generator.h b/Source/cmExtraEclipseCDT4Generator.h index ff4c59e..a7aa549 100644 --- a/Source/cmExtraEclipseCDT4Generator.h +++ b/Source/cmExtraEclipseCDT4Generator.h @@ -86,7 +86,7 @@ private: std::set<std::string>& emittedDirs); static void AddEnvVar(std::ostream& out, const char* envVar, - cmLocalGenerator* lg); + cmLocalGenerator& lg); void WriteGroups(std::vector<cmSourceGroup> const& sourceGroups, std::string& linkName, cmXMLWriter& xml); diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx index e8c9dd0..3a22846 100644 --- a/Source/cmExtraKateGenerator.cxx +++ b/Source/cmExtraKateGenerator.cxx @@ -3,6 +3,7 @@ #include "cmExtraKateGenerator.h" #include <cstring> +#include <memory> #include <ostream> #include <set> #include <vector> @@ -40,21 +41,21 @@ cmExternalMakefileProjectGeneratorFactory* cmExtraKateGenerator::GetFactory() void cmExtraKateGenerator::Generate() { - cmLocalGenerator* lg = this->GlobalGenerator->GetLocalGenerators()[0]; + const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0]; const cmMakefile* mf = lg->GetMakefile(); this->ProjectName = this->GenerateProjectName( lg->GetProjectName(), mf->GetSafeDefinition("CMAKE_BUILD_TYPE"), this->GetPathBasename(lg->GetBinaryDirectory())); this->UseNinja = (this->GlobalGenerator->GetName() == "Ninja"); - this->CreateKateProjectFile(lg); - this->CreateDummyKateProjectFile(lg); + this->CreateKateProjectFile(*lg); + this->CreateDummyKateProjectFile(*lg); } void cmExtraKateGenerator::CreateKateProjectFile( - const cmLocalGenerator* lg) const + const cmLocalGenerator& lg) const { - std::string filename = cmStrCat(lg->GetBinaryDirectory(), "/.kateproject"); + std::string filename = cmStrCat(lg.GetBinaryDirectory(), "/.kateproject"); cmGeneratedFileStream fout(filename); if (!fout) { return; @@ -64,21 +65,21 @@ void cmExtraKateGenerator::CreateKateProjectFile( fout << "{\n" "\t\"name\": \"" << this->ProjectName << "\",\n" - "\t\"directory\": \"" << lg->GetSourceDirectory() << "\",\n" + "\t\"directory\": \"" << lg.GetSourceDirectory() << "\",\n" "\t\"files\": [ { " << this->GenerateFilesString(lg) << "} ],\n"; /* clang-format on */ this->WriteTargets(lg, fout); fout << "}\n"; } -void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator* lg, +void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator& lg, cmGeneratedFileStream& fout) const { - cmMakefile const* mf = lg->GetMakefile(); + cmMakefile const* mf = lg.GetMakefile(); const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM"); const std::string& makeArgs = mf->GetSafeDefinition("CMAKE_KATE_MAKE_ARGUMENTS"); - std::string const& homeOutputDir = lg->GetBinaryDirectory(); + std::string const& homeOutputDir = lg.GetBinaryDirectory(); /* clang-format off */ fout << @@ -109,14 +110,12 @@ void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator* lg, // add all executable and library targets and some of the GLOBAL // and UTILITY targets - for (cmLocalGenerator* localGen : - this->GlobalGenerator->GetLocalGenerators()) { - const std::vector<cmGeneratorTarget*>& targets = - localGen->GetGeneratorTargets(); + for (const auto& localGen : this->GlobalGenerator->GetLocalGenerators()) { + const auto& targets = localGen->GetGeneratorTargets(); std::string currentDir = localGen->GetCurrentBinaryDirectory(); bool topLevel = (currentDir == localGen->GetBinaryDirectory()); - for (cmGeneratorTarget* target : targets) { + for (const auto& target : targets) { std::string const& targetName = target->GetName(); switch (target->GetType()) { case cmStateEnums::GLOBAL_TARGET: { @@ -205,10 +204,10 @@ void cmExtraKateGenerator::AppendTarget(cmGeneratedFileStream& fout, } void cmExtraKateGenerator::CreateDummyKateProjectFile( - const cmLocalGenerator* lg) const + const cmLocalGenerator& lg) const { std::string filename = - cmStrCat(lg->GetBinaryDirectory(), '/', this->ProjectName, ".kateproject"); + cmStrCat(lg.GetBinaryDirectory(), '/', this->ProjectName, ".kateproject"); cmGeneratedFileStream fout(filename); if (!fout) { return; @@ -219,26 +218,25 @@ void cmExtraKateGenerator::CreateDummyKateProjectFile( } std::string cmExtraKateGenerator::GenerateFilesString( - const cmLocalGenerator* lg) const + const cmLocalGenerator& lg) const { - std::string s = cmStrCat(lg->GetSourceDirectory(), "/.git"); + std::string s = cmStrCat(lg.GetSourceDirectory(), "/.git"); if (cmSystemTools::FileExists(s)) { return "\"git\": 1 "; } - s = cmStrCat(lg->GetSourceDirectory(), "/.svn"); + s = cmStrCat(lg.GetSourceDirectory(), "/.svn"); if (cmSystemTools::FileExists(s)) { return "\"svn\": 1 "; } - s = cmStrCat(lg->GetSourceDirectory(), '/'); + s = cmStrCat(lg.GetSourceDirectory(), '/'); std::set<std::string> files; std::string tmp; - const std::vector<cmLocalGenerator*>& lgs = - this->GlobalGenerator->GetLocalGenerators(); + const auto& lgs = this->GlobalGenerator->GetLocalGenerators(); - for (cmLocalGenerator* lgen : lgs) { + for (const auto& lgen : lgs) { cmMakefile* makefile = lgen->GetMakefile(); const std::vector<std::string>& listFiles = makefile->GetListFiles(); for (std::string const& listFile : listFiles) { @@ -248,8 +246,7 @@ std::string cmExtraKateGenerator::GenerateFilesString( } } - const std::vector<cmSourceFile*>& sources = makefile->GetSourceFiles(); - for (cmSourceFile* sf : sources) { + for (const auto& sf : makefile->GetSourceFiles()) { if (sf->GetIsGenerated()) { continue; } diff --git a/Source/cmExtraKateGenerator.h b/Source/cmExtraKateGenerator.h index be1376a..1fb81b4 100644 --- a/Source/cmExtraKateGenerator.h +++ b/Source/cmExtraKateGenerator.h @@ -25,16 +25,16 @@ public: void Generate() override; private: - void CreateKateProjectFile(const cmLocalGenerator* lg) const; - void CreateDummyKateProjectFile(const cmLocalGenerator* lg) const; - void WriteTargets(const cmLocalGenerator* lg, + void CreateKateProjectFile(const cmLocalGenerator& lg) const; + void CreateDummyKateProjectFile(const cmLocalGenerator& lg) const; + void WriteTargets(const cmLocalGenerator& lg, cmGeneratedFileStream& fout) const; void AppendTarget(cmGeneratedFileStream& fout, const std::string& target, const std::string& make, const std::string& makeArgs, const std::string& path, const std::string& homeOutputDir) const; - std::string GenerateFilesString(const cmLocalGenerator* lg) const; + std::string GenerateFilesString(const cmLocalGenerator& lg) const; std::string GetPathBasename(const std::string& path) const; std::string GenerateProjectName(const std::string& name, const std::string& type, diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 495324c..413449c 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -3,6 +3,7 @@ #include "cmExtraSublimeTextGenerator.h" #include <cstring> +#include <memory> #include <set> #include <sstream> #include <utility> @@ -182,8 +183,8 @@ void cmExtraSublimeTextGenerator::AppendAllTargets( // and UTILITY targets for (cmLocalGenerator* lg : lgs) { cmMakefile* makefile = lg->GetMakefile(); - const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { + const auto& targets = lg->GetGeneratorTargets(); + for (const auto& target : targets) { std::string targetName = target->GetName(); switch (target->GetType()) { case cmStateEnums::GLOBAL_TARGET: { @@ -216,11 +217,11 @@ void cmExtraSublimeTextGenerator::AppendAllTargets( case cmStateEnums::SHARED_LIBRARY: case cmStateEnums::MODULE_LIBRARY: case cmStateEnums::OBJECT_LIBRARY: { - this->AppendTarget(fout, targetName, lg, target, make.c_str(), + this->AppendTarget(fout, targetName, lg, target.get(), make.c_str(), makefile, compiler.c_str(), sourceFileFlags, false); std::string fastTarget = cmStrCat(targetName, "/fast"); - this->AppendTarget(fout, fastTarget, lg, target, make.c_str(), + this->AppendTarget(fout, fastTarget, lg, target.get(), make.c_str(), makefile, compiler.c_str(), sourceFileFlags, false); } break; @@ -296,8 +297,7 @@ void cmExtraSublimeTextGenerator::AppendTarget( fout << "\t{\n\t\t\t\"name\": \"" << lg->GetProjectName() << " - " << targetName << "\",\n"; fout << "\t\t\t\"cmd\": [" - << this->BuildMakeCommand(make, makefileName.c_str(), targetName) - << "],\n"; + << this->BuildMakeCommand(make, makefileName, targetName) << "],\n"; fout << "\t\t\t\"working_dir\": \"${project_path}\",\n"; fout << "\t\t\t\"file_regex\": \"" "^(..[^:]*)(?::|\\\\()([0-9]+)(?::|\\\\))(?:([0-9]+):)?\\\\s*(.*)" @@ -308,7 +308,8 @@ void cmExtraSublimeTextGenerator::AppendTarget( // Create the command line for building the given target using the selected // make std::string cmExtraSublimeTextGenerator::BuildMakeCommand( - const std::string& make, const char* makefile, const std::string& target) + const std::string& make, const std::string& makefile, + const std::string& target) { std::string command = cmStrCat('"', make, '"'); std::string generator = this->GlobalGenerator->GetName(); diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h index 7e8f2d4..078cfe7 100644 --- a/Source/cmExtraSublimeTextGenerator.h +++ b/Source/cmExtraSublimeTextGenerator.h @@ -44,7 +44,8 @@ private: /** Returns the build command that needs to be executed to build the * specified target. */ - std::string BuildMakeCommand(const std::string& make, const char* makefile, + std::string BuildMakeCommand(const std::string& make, + const std::string& makefile, const std::string& target); /** Appends the specified target to the generated project file as a Sublime * Text build system. diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx index 11844e4..d88617a 100644 --- a/Source/cmFLTKWrapUICommand.cxx +++ b/Source/cmFLTKWrapUICommand.cxx @@ -6,15 +6,20 @@ #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" +#include "cmListFileCache.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmRange.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmake.h" class cmTarget; -static void FinalAction(cmMakefile& makefile, std::string const& name) +static void FinalAction(cmMakefile& makefile, std::string const& name, + const cmListFileBacktrace& lfbt) { // people should add the srcs to the target themselves, but the old command // didn't support that, so check and see if they added the files in and if @@ -26,7 +31,8 @@ static void FinalAction(cmMakefile& makefile, std::string const& name) ". The problem was found while processing the source directory: ", makefile.GetCurrentSourceDirectory(), ". This FLTK_WRAP_UI call will be ignored."); - cmSystemTools::Message(msg, "Warning"); + makefile.GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_ERROR, msg, + lfbt); } } @@ -116,7 +122,9 @@ bool cmFLTKWrapUICommand(std::vector<std::string> const& args, std::string const varName = target + "_FLTK_UI_SRCS"; mf.AddDefinition(varName, sourceListValue); - mf.AddFinalAction( - [target](cmMakefile& makefile) { FinalAction(makefile, target); }); + mf.AddGeneratorAction( + [target](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) { + FinalAction(*lg.GetMakefile(), target, lfbt); + }); return true; } diff --git a/Source/cmFileAPICMakeFiles.cxx b/Source/cmFileAPICMakeFiles.cxx index f419997..44ba96c 100644 --- a/Source/cmFileAPICMakeFiles.cxx +++ b/Source/cmFileAPICMakeFiles.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmFileAPICMakeFiles.h" +#include <memory> #include <string> #include <vector> @@ -67,7 +68,7 @@ Json::Value CMakeFiles::DumpInputs() cmGlobalGenerator* gg = this->FileAPI.GetCMakeInstance()->GetGlobalGenerator(); - for (cmLocalGenerator const* lg : gg->GetLocalGenerators()) { + for (const auto& lg : gg->GetLocalGenerators()) { cmMakefile const* mf = lg->GetMakefile(); for (std::string const& file : mf->GetListFiles()) { inputs.append(this->DumpInput(file)); diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index d7993c7..955195f 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -15,9 +15,10 @@ #include <utility> #include <vector> +#include <cmext/algorithm> + #include "cm_jsoncpp_value.h" -#include "cmAlgorithms.h" #include "cmCryptoHash.h" #include "cmFileAPI.h" #include "cmGeneratorExpression.h" @@ -426,7 +427,7 @@ Json::Value Codemodel::DumpConfigurations() Json::Value configurations = Json::arrayValue; cmGlobalGenerator* gg = this->FileAPI.GetCMakeInstance()->GetGlobalGenerator(); - auto makefiles = gg->GetMakefiles(); + const auto& makefiles = gg->GetMakefiles(); if (!makefiles.empty()) { std::vector<std::string> const& configs = makefiles[0]->GetGeneratorConfigs(); @@ -469,17 +470,17 @@ void CodemodelConfig::ProcessDirectories() { cmGlobalGenerator* gg = this->FileAPI.GetCMakeInstance()->GetGlobalGenerator(); - std::vector<cmLocalGenerator*> const& localGens = gg->GetLocalGenerators(); + auto const& localGens = gg->GetLocalGenerators(); // Add directories in forward order to process parents before children. this->Directories.reserve(localGens.size()); - for (cmLocalGenerator* lg : localGens) { + for (const auto& lg : localGens) { auto directoryIndex = static_cast<Json::ArrayIndex>(this->Directories.size()); this->Directories.emplace_back(); Directory& d = this->Directories[directoryIndex]; d.Snapshot = lg->GetStateSnapshot().GetBuildsystemDirectory(); - d.LocalGenerator = lg; + d.LocalGenerator = lg.get(); this->DirectoryMap[d.Snapshot] = directoryIndex; d.ProjectIndex = this->AddProject(d.Snapshot); @@ -492,8 +493,9 @@ void CodemodelConfig::ProcessDirectories() Directory& d = *di; // Accumulate the presence of install rules on the way up. - for (auto gen : d.LocalGenerator->GetMakefile()->GetInstallGenerators()) { - if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(gen)) { + for (const auto& gen : + d.LocalGenerator->GetMakefile()->GetInstallGenerators()) { + if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(gen.get())) { d.HasInstallRule = true; break; } @@ -554,8 +556,8 @@ Json::Value CodemodelConfig::DumpTargets() std::vector<cmGeneratorTarget*> targetList; cmGlobalGenerator* gg = this->FileAPI.GetCMakeInstance()->GetGlobalGenerator(); - for (cmLocalGenerator const* lg : gg->GetLocalGenerators()) { - cmAppend(targetList, lg->GetGeneratorTargets()); + for (const auto& lg : gg->GetLocalGenerators()) { + cm::append(targetList, lg->GetGeneratorTargets()); } std::sort(targetList.begin(), targetList.end(), [](cmGeneratorTarget* l, cmGeneratorTarget* r) { diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index d45414f..3b532c8 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -15,6 +15,7 @@ #include <vector> #include <cm/memory> +#include <cmext/algorithm> #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" @@ -32,12 +33,14 @@ #include "cmFileInstaller.h" #include "cmFileLockPool.h" #include "cmFileTimes.h" +#include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" #include "cmHexFileConverter.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmNewLineStyle.h" #include "cmPolicies.h" #include "cmRange.h" #include "cmRuntimeDependencyArchive.h" @@ -783,7 +786,7 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse, } std::vector<std::string>& foundFiles = g.GetFiles(); - cmAppend(files, foundFiles); + cm::append(files, foundFiles); if (configureDepends) { std::sort(foundFiles.begin(), foundFiles.end()); @@ -1394,8 +1397,8 @@ size_t cmWriteToMemoryCallback(void* ptr, size_t size, size_t nmemb, { int realsize = static_cast<int>(size * nmemb); const char* chPtr = static_cast<char*>(ptr); - cmAppend(*static_cast<cmFileCommandVectorOfChar*>(data), chPtr, - chPtr + realsize); + cm::append(*static_cast<cmFileCommandVectorOfChar*>(data), chPtr, + chPtr + realsize); return realsize; } @@ -1408,7 +1411,7 @@ size_t cmFileCommandCurlDebugCallback(CURL*, curl_infotype type, char* chPtr, case CURLINFO_TEXT: case CURLINFO_HEADER_IN: case CURLINFO_HEADER_OUT: - cmAppend(vec, chPtr, chPtr + size); + cm::append(vec, chPtr, chPtr + size); break; case CURLINFO_DATA_IN: case CURLINFO_DATA_OUT: @@ -1418,7 +1421,7 @@ size_t cmFileCommandCurlDebugCallback(CURL*, curl_infotype type, char* chPtr, int n = sprintf(buf, "[%" KWIML_INT_PRIu64 " bytes data]\n", static_cast<KWIML_INT_uint64_t>(size)); if (n > 0) { - cmAppend(vec, buf, buf + n); + cm::append(vec, buf, buf + n); } } break; default: @@ -1707,7 +1710,8 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, // as we receive downloaded bits from curl... // std::string dir = cmSystemTools::GetFilenamePath(file); - if (!cmSystemTools::FileExists(dir) && !cmSystemTools::MakeDirectory(dir)) { + if (!dir.empty() && !cmSystemTools::FileExists(dir) && + !cmSystemTools::MakeDirectory(dir)) { std::string errstring = "DOWNLOAD error: cannot create directory '" + dir + "' - Specify file by full path name and verify that you " "have directory creation and file write privileges."; @@ -2774,6 +2778,121 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, return true; } +bool HandleConfigureCommand(std::vector<std::string> const& args, + cmExecutionStatus& status) +{ + if (args.size() < 5) { + status.SetError("Incorrect arguments to CONFIGURE subcommand."); + return false; + } + if (args[1] != "OUTPUT") { + status.SetError("Incorrect arguments to CONFIGURE subcommand."); + return false; + } + if (args[3] != "CONTENT") { + status.SetError("Incorrect arguments to CONFIGURE subcommand."); + return false; + } + + std::string errorMessage; + cmNewLineStyle newLineStyle; + if (!newLineStyle.ReadFromArguments(args, errorMessage)) { + status.SetError(cmStrCat("CONFIGURE ", errorMessage)); + return false; + } + + bool escapeQuotes = false; + bool atOnly = false; + for (unsigned int i = 5; i < args.size(); ++i) { + if (args[i] == "@ONLY") { + atOnly = true; + } else if (args[i] == "ESCAPE_QUOTES") { + escapeQuotes = true; + } else if (args[i] == "NEWLINE_STYLE" || args[i] == "LF" || + args[i] == "UNIX" || args[i] == "CRLF" || args[i] == "WIN32" || + args[i] == "DOS") { + /* Options handled by NewLineStyle member above. */ + } else { + status.SetError( + cmStrCat("CONFIGURE Unrecognized argument \"", args[i], "\"")); + return false; + } + } + + // Check for generator expressions + const std::string input = args[4]; + std::string outputFile = args[2]; + + std::string::size_type pos = input.find_first_of("<>"); + if (pos != std::string::npos) { + status.SetError(cmStrCat("CONFIGURE called with CONTENT containing a \"", + input[pos], + "\". This character is not allowed.")); + return false; + } + + pos = outputFile.find_first_of("<>"); + if (pos != std::string::npos) { + status.SetError(cmStrCat("CONFIGURE called with OUTPUT containing a \"", + outputFile[pos], + "\". This character is not allowed.")); + return false; + } + + cmMakefile& makeFile = status.GetMakefile(); + if (!makeFile.CanIWriteThisFile(outputFile)) { + cmSystemTools::Error("Attempt to write file: " + outputFile + + " into a source directory."); + return false; + } + + cmSystemTools::ConvertToUnixSlashes(outputFile); + + // Re-generate if non-temporary outputs are missing. + // when we finalize the configuration we will remove all + // output files that now don't exist. + makeFile.AddCMakeOutputFile(outputFile); + + // Create output directory + const std::string::size_type slashPos = outputFile.rfind('/'); + if (slashPos != std::string::npos) { + const std::string path = outputFile.substr(0, slashPos); + cmSystemTools::MakeDirectory(path); + } + + std::string newLineCharacters; + bool open_with_binary_flag = false; + if (newLineStyle.IsValid()) { + open_with_binary_flag = true; + newLineCharacters = newLineStyle.GetCharacters(); + } + + cmGeneratedFileStream fout; + fout.Open(outputFile, false, open_with_binary_flag); + if (!fout) { + cmSystemTools::Error("Could not open file for write in copy operation " + + outputFile); + cmSystemTools::ReportLastSystemError(""); + return false; + } + fout.SetCopyIfDifferent(true); + + // copy intput to output and expand variables from input at the same time + std::stringstream sin(input, std::ios::in); + std::string inLine; + std::string outLine; + while (cmSystemTools::GetLineFromStream(sin, inLine)) { + outLine.clear(); + makeFile.ConfigureString(inLine, outLine, atOnly, escapeQuotes); + fout << outLine << newLineCharacters; + } + + // close file before attempting to copy + fout.close(); + + return true; +} + } // namespace bool cmFileCommand(std::vector<std::string> const& args, @@ -2827,6 +2946,7 @@ bool cmFileCommand(std::vector<std::string> const& args, { "READ_SYMLINK"_s, HandleReadSymlinkCommand }, { "CREATE_LINK"_s, HandleCreateLinkCommand }, { "GET_RUNTIME_DEPENDENCIES"_s, HandleGetRuntimeDependenciesCommand }, + { "CONFIGURE"_s, HandleConfigureCommand }, }; return subcommand(args[0], args, status); diff --git a/Source/cmFileLock.cxx b/Source/cmFileLock.cxx index e90f571..6010233 100644 --- a/Source/cmFileLock.cxx +++ b/Source/cmFileLock.cxx @@ -3,11 +3,23 @@ #include "cmFileLock.h" #include <cassert> +#include <utility> #include "cmFileLockResult.h" // Common implementation +cmFileLock::cmFileLock(cmFileLock&& other) noexcept +{ + this->File = other.File; +#if defined(_WIN32) + other.File = INVALID_HANDLE_VALUE; +#else + other.File = -1; +#endif + this->Filename = std::move(other.Filename); +} + cmFileLock::~cmFileLock() { if (!this->Filename.empty()) { @@ -17,6 +29,19 @@ cmFileLock::~cmFileLock() } } +cmFileLock& cmFileLock::operator=(cmFileLock&& other) noexcept +{ + this->File = other.File; +#if defined(_WIN32) + other.File = INVALID_HANDLE_VALUE; +#else + other.File = -1; +#endif + this->Filename = std::move(other.Filename); + + return *this; +} + cmFileLockResult cmFileLock::Lock(const std::string& filename, unsigned long timeout) { diff --git a/Source/cmFileLock.h b/Source/cmFileLock.h index 2130d65..5fe068e 100644 --- a/Source/cmFileLock.h +++ b/Source/cmFileLock.h @@ -26,7 +26,9 @@ public: ~cmFileLock(); cmFileLock(cmFileLock const&) = delete; + cmFileLock(cmFileLock&&) noexcept; cmFileLock& operator=(cmFileLock const&) = delete; + cmFileLock& operator=(cmFileLock&&) noexcept; /** * @brief Lock the file. diff --git a/Source/cmFileLockPool.cxx b/Source/cmFileLockPool.cxx index 8db2db2..e1f6e94 100644 --- a/Source/cmFileLockPool.cxx +++ b/Source/cmFileLockPool.cxx @@ -3,40 +3,34 @@ #include "cmFileLockPool.h" #include <cassert> +#include <utility> -#include "cmAlgorithms.h" #include "cmFileLock.h" #include "cmFileLockResult.h" cmFileLockPool::cmFileLockPool() = default; -cmFileLockPool::~cmFileLockPool() -{ - cmDeleteAll(this->FunctionScopes); - cmDeleteAll(this->FileScopes); -} +cmFileLockPool::~cmFileLockPool() = default; void cmFileLockPool::PushFunctionScope() { - this->FunctionScopes.push_back(new ScopePool()); + this->FunctionScopes.push_back(ScopePool()); } void cmFileLockPool::PopFunctionScope() { assert(!this->FunctionScopes.empty()); - delete this->FunctionScopes.back(); this->FunctionScopes.pop_back(); } void cmFileLockPool::PushFileScope() { - this->FileScopes.push_back(new ScopePool()); + this->FileScopes.push_back(ScopePool()); } void cmFileLockPool::PopFileScope() { assert(!this->FileScopes.empty()); - delete this->FileScopes.back(); this->FileScopes.pop_back(); } @@ -49,7 +43,7 @@ cmFileLockResult cmFileLockPool::LockFunctionScope(const std::string& filename, if (this->FunctionScopes.empty()) { return cmFileLockResult::MakeNoFunction(); } - return this->FunctionScopes.back()->Lock(filename, timeoutSec); + return this->FunctionScopes.back().Lock(filename, timeoutSec); } cmFileLockResult cmFileLockPool::LockFileScope(const std::string& filename, @@ -59,7 +53,7 @@ cmFileLockResult cmFileLockPool::LockFileScope(const std::string& filename, return cmFileLockResult::MakeAlreadyLocked(); } assert(!this->FileScopes.empty()); - return this->FileScopes.back()->Lock(filename, timeoutSec); + return this->FileScopes.back().Lock(filename, timeoutSec); } cmFileLockResult cmFileLockPool::LockProcessScope(const std::string& filename, @@ -74,14 +68,14 @@ cmFileLockResult cmFileLockPool::LockProcessScope(const std::string& filename, cmFileLockResult cmFileLockPool::Release(const std::string& filename) { for (auto& funcScope : this->FunctionScopes) { - const cmFileLockResult result = funcScope->Release(filename); + const cmFileLockResult result = funcScope.Release(filename); if (!result.IsOk()) { return result; } } for (auto& fileScope : this->FileScopes) { - const cmFileLockResult result = fileScope->Release(filename); + const cmFileLockResult result = fileScope.Release(filename); if (!result.IsOk()) { return result; } @@ -93,14 +87,14 @@ cmFileLockResult cmFileLockPool::Release(const std::string& filename) bool cmFileLockPool::IsAlreadyLocked(const std::string& filename) const { for (auto const& funcScope : this->FunctionScopes) { - const bool result = funcScope->IsAlreadyLocked(filename); + const bool result = funcScope.IsAlreadyLocked(filename); if (result) { return true; } } for (auto const& fileScope : this->FileScopes) { - const bool result = fileScope->IsAlreadyLocked(filename); + const bool result = fileScope.IsAlreadyLocked(filename); if (result) { return true; } @@ -111,21 +105,29 @@ bool cmFileLockPool::IsAlreadyLocked(const std::string& filename) const cmFileLockPool::ScopePool::ScopePool() = default; -cmFileLockPool::ScopePool::~ScopePool() +cmFileLockPool::ScopePool::~ScopePool() = default; + +cmFileLockPool::ScopePool::ScopePool(ScopePool&&) noexcept = default; + +cmFileLockPool::ScopePool& cmFileLockPool::ScopePool::operator=( + ScopePool&& other) noexcept { - cmDeleteAll(this->Locks); + if (this != &other) { + this->Locks = std::move(other.Locks); + } + + return *this; } cmFileLockResult cmFileLockPool::ScopePool::Lock(const std::string& filename, unsigned long timeoutSec) { - cmFileLock* lock = new cmFileLock(); - const cmFileLockResult result = lock->Lock(filename, timeoutSec); + cmFileLock lock; + const cmFileLockResult result = lock.Lock(filename, timeoutSec); if (result.IsOk()) { - this->Locks.push_back(lock); + this->Locks.push_back(std::move(lock)); return cmFileLockResult::MakeOk(); } - delete lock; return result; } @@ -133,8 +135,8 @@ cmFileLockResult cmFileLockPool::ScopePool::Release( const std::string& filename) { for (auto& lock : this->Locks) { - if (lock->IsLocked(filename)) { - return lock->Release(); + if (lock.IsLocked(filename)) { + return lock.Release(); } } return cmFileLockResult::MakeOk(); @@ -144,7 +146,7 @@ bool cmFileLockPool::ScopePool::IsAlreadyLocked( const std::string& filename) const { for (auto const& lock : this->Locks) { - if (lock->IsLocked(filename)) { + if (lock.IsLocked(filename)) { return true; } } diff --git a/Source/cmFileLockPool.h b/Source/cmFileLockPool.h index dae68dd..d45c82c 100644 --- a/Source/cmFileLockPool.h +++ b/Source/cmFileLockPool.h @@ -8,7 +8,8 @@ #include <string> #include <vector> -class cmFileLock; +#include "cmFileLock.h" + class cmFileLockResult; class cmFileLockPool @@ -64,7 +65,9 @@ private: ~ScopePool(); ScopePool(ScopePool const&) = delete; + ScopePool(ScopePool&&) noexcept; ScopePool& operator=(ScopePool const&) = delete; + ScopePool& operator=(ScopePool&&) noexcept; cmFileLockResult Lock(const std::string& filename, unsigned long timeoutSec); @@ -72,17 +75,12 @@ private: bool IsAlreadyLocked(const std::string& filename) const; private: - using List = std::vector<cmFileLock*>; - using It = List::iterator; - using CIt = List::const_iterator; + using List = std::vector<cmFileLock>; List Locks; }; - using List = std::vector<ScopePool*>; - - using It = List::iterator; - using CIt = List::const_iterator; + using List = std::vector<ScopePool>; List FunctionScopes; List FileScopes; diff --git a/Source/cmFileMonitor.cxx b/Source/cmFileMonitor.cxx index ac8a37e..8cfdb2d 100644 --- a/Source/cmFileMonitor.cxx +++ b/Source/cmFileMonitor.cxx @@ -7,9 +7,9 @@ #include <unordered_map> #include <utility> -#include "cmsys/SystemTools.hxx" +#include <cm/memory> -#include "cmAlgorithms.h" +#include "cmsys/SystemTools.hxx" namespace { void on_directory_change(uv_fs_event_t* handle, const char* filename, @@ -37,12 +37,12 @@ public: class cmVirtualDirectoryWatcher : public cmIBaseWatcher { public: - ~cmVirtualDirectoryWatcher() override { cmDeleteAll(this->Children); } + ~cmVirtualDirectoryWatcher() override = default; cmIBaseWatcher* Find(const std::string& ps) { const auto i = this->Children.find(ps); - return (i == this->Children.end()) ? nullptr : i->second; + return (i == this->Children.end()) ? nullptr : i->second.get(); } void Trigger(const std::string& pathSegment, int events, @@ -96,11 +96,7 @@ public: return result; } - void Reset() - { - cmDeleteAll(this->Children); - this->Children.clear(); - } + void Reset() { this->Children.clear(); } void AddChildWatcher(const std::string& ps, cmIBaseWatcher* watcher) { @@ -108,11 +104,12 @@ public: assert(this->Children.find(ps) == this->Children.end()); assert(watcher); - this->Children.emplace(std::make_pair(ps, watcher)); + this->Children.emplace(ps, std::unique_ptr<cmIBaseWatcher>(watcher)); } private: - std::unordered_map<std::string, cmIBaseWatcher*> Children; // owned! + std::unordered_map<std::string, std::unique_ptr<cmIBaseWatcher>> + Children; // owned! }; // Root of all the different (on windows!) root directories: @@ -295,14 +292,11 @@ void on_fs_close(uv_handle_t* handle) } // namespace cmFileMonitor::cmFileMonitor(uv_loop_t* l) - : Root(new cmRootWatcher(l)) + : Root(cm::make_unique<cmRootWatcher>(l)) { } -cmFileMonitor::~cmFileMonitor() -{ - delete this->Root; -} +cmFileMonitor::~cmFileMonitor() = default; void cmFileMonitor::MonitorPaths(const std::vector<std::string>& paths, Callback const& cb) @@ -316,7 +310,7 @@ void cmFileMonitor::MonitorPaths(const std::vector<std::string>& paths, if (segmentCount < 2) { // Expect at least rootdir and filename continue; } - cmVirtualDirectoryWatcher* currentWatcher = this->Root; + cmVirtualDirectoryWatcher* currentWatcher = this->Root.get(); for (size_t i = 0; i < segmentCount; ++i) { assert(currentWatcher); @@ -334,11 +328,12 @@ void cmFileMonitor::MonitorPaths(const std::vector<std::string>& paths, cmIBaseWatcher* nextWatcher = currentWatcher->Find(currentSegment); if (!nextWatcher) { if (rootSegment) { // Root part - assert(currentWatcher == this->Root); - nextWatcher = new cmRootDirectoryWatcher(this->Root, currentSegment); + assert(currentWatcher == this->Root.get()); + nextWatcher = + new cmRootDirectoryWatcher(this->Root.get(), currentSegment); assert(currentWatcher->Find(currentSegment) == nextWatcher); } else if (fileSegment) { // File part - assert(currentWatcher != this->Root); + assert(currentWatcher != this->Root.get()); nextWatcher = new cmFileWatcher( dynamic_cast<cmRealDirectoryWatcher*>(currentWatcher), currentSegment, cb); diff --git a/Source/cmFileMonitor.h b/Source/cmFileMonitor.h index 7ffc929..b510a2c 100644 --- a/Source/cmFileMonitor.h +++ b/Source/cmFileMonitor.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <functional> +#include <memory> #include <string> #include <vector> @@ -30,5 +31,5 @@ public: std::vector<std::string> WatchedDirectories() const; private: - cmRootWatcher* Root; + std::unique_ptr<cmRootWatcher> Root; }; diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx index 7d74118..fb09b33 100644 --- a/Source/cmFindBase.cxx +++ b/Source/cmFindBase.cxx @@ -4,10 +4,11 @@ #include <cstddef> #include <deque> -#include <iostream> #include <map> +#include <utility> + +#include <cmext/algorithm> -#include "cmAlgorithms.h" #include "cmMakefile.h" #include "cmRange.h" #include "cmSearchPath.h" @@ -21,10 +22,6 @@ class cmExecutionStatus; cmFindBase::cmFindBase(cmExecutionStatus& status) : cmFindCommon(status) { - this->AlreadyInCache = false; - this->AlreadyInCacheWithoutMetaInfo = false; - this->NamesPerDir = false; - this->NamesPerDirAllowed = false; } bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn) @@ -114,19 +111,25 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn) } else if (args[j] == "NO_SYSTEM_PATH") { doing = DoingNone; this->NoDefaultPath = true; + } else if (args[j] == "REQUIRED") { + doing = DoingNone; + this->Required = true; + newStyle = true; } else if (this->CheckCommonArgument(args[j])) { doing = DoingNone; + } else { // Some common arguments were accidentally supported by CMake // 2.4 and 2.6.0 in the short-hand form of the command, so we // must support it even though it is not documented. - } else if (doing == DoingNames) { - this->Names.push_back(args[j]); - } else if (doing == DoingPaths) { - this->UserGuessArgs.push_back(args[j]); - } else if (doing == DoingHints) { - this->UserHintsArgs.push_back(args[j]); - } else if (doing == DoingPathSuffixes) { - this->AddPathSuffix(args[j]); + if (doing == DoingNames) { + this->Names.push_back(args[j]); + } else if (doing == DoingPaths) { + this->UserGuessArgs.push_back(args[j]); + } else if (doing == DoingHints) { + this->UserHintsArgs.push_back(args[j]); + } else if (doing == DoingPathSuffixes) { + this->AddPathSuffix(args[j]); + } } } @@ -153,7 +156,7 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn) std::vector<std::string> shortArgs = this->Names; this->Names.clear(); // clear out any values in Names this->Names.push_back(shortArgs[0]); - cmAppend(this->UserGuessArgs, shortArgs.begin() + 1, shortArgs.end()); + cm::append(this->UserGuessArgs, shortArgs.begin() + 1, shortArgs.end()); } this->ExpandPaths(); @@ -288,33 +291,6 @@ void cmFindBase::FillUserGuessPath() paths.AddSuffixes(this->SearchPathSuffixes); } -void cmFindBase::PrintFindStuff() -{ - std::cerr << "SearchFrameworkLast: " << this->SearchFrameworkLast << "\n"; - std::cerr << "SearchFrameworkOnly: " << this->SearchFrameworkOnly << "\n"; - std::cerr << "SearchFrameworkFirst: " << this->SearchFrameworkFirst << "\n"; - std::cerr << "SearchAppBundleLast: " << this->SearchAppBundleLast << "\n"; - std::cerr << "SearchAppBundleOnly: " << this->SearchAppBundleOnly << "\n"; - std::cerr << "SearchAppBundleFirst: " << this->SearchAppBundleFirst << "\n"; - std::cerr << "VariableName " << this->VariableName << "\n"; - std::cerr << "VariableDocumentation " << this->VariableDocumentation << "\n"; - std::cerr << "NoDefaultPath " << this->NoDefaultPath << "\n"; - std::cerr << "NoCMakeEnvironmentPath " << this->NoCMakeEnvironmentPath - << "\n"; - std::cerr << "NoCMakePath " << this->NoCMakePath << "\n"; - std::cerr << "NoSystemEnvironmentPath " << this->NoSystemEnvironmentPath - << "\n"; - std::cerr << "NoCMakeSystemPath " << this->NoCMakeSystemPath << "\n"; - std::cerr << "EnvironmentPath " << this->EnvironmentPath << "\n"; - std::cerr << "CMakePathName " << this->CMakePathName << "\n"; - std::cerr << "Names " << cmJoin(this->Names, " ") << "\n"; - std::cerr << "\n"; - std::cerr << "SearchPathSuffixes "; - std::cerr << cmJoin(this->SearchPathSuffixes, "\n") << "\n"; - std::cerr << "SearchPaths\n"; - std::cerr << cmWrap("[", this->SearchPaths, "]", "\n") << "\n"; -} - bool cmFindBase::CheckForVariableInCache() { if (const char* cacheValue = @@ -343,3 +319,87 @@ bool cmFindBase::CheckForVariableInCache() } return false; } + +cmFindBaseDebugState::cmFindBaseDebugState(std::string commandName, + cmFindBase const* findBase) + : FindCommand(findBase) + , CommandName(std::move(commandName)) +{ +} + +cmFindBaseDebugState::~cmFindBaseDebugState() +{ + if (this->FindCommand->DebugMode) { + std::string buffer = + cmStrCat(this->CommandName, " called with the following settings:\n"); + buffer += cmStrCat(" VAR: ", this->FindCommand->VariableName, "\n"); + buffer += cmStrCat( + " NAMES: ", cmWrap("\"", this->FindCommand->Names, "\"", "\n "), + "\n"); + buffer += cmStrCat( + " Documentation: ", this->FindCommand->VariableDocumentation, "\n"); + buffer += " Framework\n"; + buffer += cmStrCat(" Only Search Frameworks: ", + this->FindCommand->SearchFrameworkOnly, "\n"); + + buffer += cmStrCat(" Search Frameworks Last: ", + this->FindCommand->SearchFrameworkLast, "\n"); + buffer += cmStrCat(" Search Frameworks First: ", + this->FindCommand->SearchFrameworkFirst, "\n"); + buffer += " AppBundle\n"; + buffer += cmStrCat(" Only Search AppBundle: ", + this->FindCommand->SearchAppBundleOnly, "\n"); + buffer += cmStrCat(" Search AppBundle Last: ", + this->FindCommand->SearchAppBundleLast, "\n"); + buffer += cmStrCat(" Search AppBundle First: ", + this->FindCommand->SearchAppBundleFirst, "\n"); + + if (this->FindCommand->NoDefaultPath) { + buffer += " NO_DEFAULT_PATH Enabled\n"; + } else { + buffer += cmStrCat( + " CMAKE_FIND_USE_CMAKE_PATH: ", !this->FindCommand->NoCMakePath, "\n", + " CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: ", + !this->FindCommand->NoCMakeEnvironmentPath, "\n", + " CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: ", + !this->FindCommand->NoSystemEnvironmentPath, "\n", + " CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: ", + !this->FindCommand->NoCMakeSystemPath, "\n"); + } + + buffer += + cmStrCat(this->CommandName, " considered the following locations:\n"); + for (auto const& state : this->FailedSearchLocations) { + std::string path = cmStrCat(" ", state.path); + if (!state.regexName.empty()) { + path = cmStrCat(path, "/", state.regexName); + } + buffer += cmStrCat(path, "\n"); + } + + if (!this->FoundSearchLocation.path.empty()) { + buffer += cmStrCat("The item was found at\n ", + this->FoundSearchLocation.path, "\n"); + } else { + buffer += "The item was not found.\n"; + } + + this->FindCommand->DebugMessage(buffer); + } +} + +void cmFindBaseDebugState::FoundAt(std::string const& path, + std::string regexName) +{ + if (this->FindCommand->DebugMode) { + this->FoundSearchLocation = DebugLibState{ std::move(regexName), path }; + } +} + +void cmFindBaseDebugState::FailedAt(std::string const& path, + std::string regexName) +{ + if (this->FindCommand->DebugMode) { + this->FailedSearchLocations.emplace_back(std::move(regexName), path); + } +} diff --git a/Source/cmFindBase.h b/Source/cmFindBase.h index f75db5f..4cbf09e 100644 --- a/Source/cmFindBase.h +++ b/Source/cmFindBase.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <string> +#include <utility> #include <vector> #include "cmFindCommon.h" @@ -31,7 +32,7 @@ public: virtual bool ParseArguments(std::vector<std::string> const& args); protected: - void PrintFindStuff(); + friend class cmFindBaseDebugState; void ExpandPaths(); // see if the VariableName is already set in the cache, @@ -43,14 +44,16 @@ protected: std::string VariableDocumentation; std::string VariableName; std::vector<std::string> Names; - bool NamesPerDir; - bool NamesPerDirAllowed; + bool NamesPerDir = false; + bool NamesPerDirAllowed = false; // CMAKE_*_PATH CMAKE_SYSTEM_*_PATH FRAMEWORK|LIBRARY|INCLUDE|PROGRAM std::string EnvironmentPath; // LIB,INCLUDE - bool AlreadyInCache; - bool AlreadyInCacheWithoutMetaInfo; + bool AlreadyInCache = false; + bool AlreadyInCacheWithoutMetaInfo = false; + + bool Required = false; private: // Add pieces of the search. @@ -63,4 +66,33 @@ private: void FillUserGuessPath(); }; +class cmFindBaseDebugState +{ +public: + explicit cmFindBaseDebugState(std::string name, cmFindBase const* findBase); + ~cmFindBaseDebugState(); + + void FoundAt(std::string const& path, std::string regexName = std::string()); + void FailedAt(std::string const& path, + std::string regexName = std::string()); + +private: + struct DebugLibState + { + DebugLibState() = default; + DebugLibState(std::string&& n, std::string p) + : regexName(n) + , path(std::move(p)) + { + } + std::string regexName; + std::string path; + }; + + cmFindBase const* FindCommand; + std::string CommandName; + std::vector<DebugLibState> FailedSearchLocations; + DebugLibState FoundSearchLocation; +}; + #endif diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index badec55..82acfed 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -7,11 +7,14 @@ #include <cstring> #include <utility> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmExecutionStatus.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmake.h" cmFindCommon::PathGroup cmFindCommon::PathGroup::All("ALL"); cmFindCommon::PathLabel cmFindCommon::PathLabel::PackageRoot( @@ -52,6 +55,8 @@ cmFindCommon::cmFindCommon(cmExecutionStatus& status) this->SearchAppBundleLast = false; this->InitializeSearchPathGroups(); + + this->DebugMode = false; } void cmFindCommon::SetError(std::string const& e) @@ -59,6 +64,19 @@ void cmFindCommon::SetError(std::string const& e) this->Status.SetError(e); } +void cmFindCommon::DebugMessage(std::string const& msg) const +{ + if (this->Makefile) { + this->Makefile->IssueMessage(MessageType::LOG, msg); + } +} + +bool cmFindCommon::ComputeIfDebugModeWanted() +{ + return this->Makefile->IsOn("CMAKE_FIND_DEBUG_MODE") || + this->Makefile->GetCMakeInstance()->GetDebugFindOutput(); +} + void cmFindCommon::InitializeSearchPathGroups() { std::vector<PathLabel>* labels; @@ -249,7 +267,7 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths) // If searching both rooted and unrooted paths add the original // paths again. if (this->FindRootPathMode == RootPathModeBoth) { - cmAppend(paths, unrootedPaths); + cm::append(paths, unrootedPaths); } } diff --git a/Source/cmFindCommon.h b/Source/cmFindCommon.h index 8177eac..916f3bc 100644 --- a/Source/cmFindCommon.h +++ b/Source/cmFindCommon.h @@ -30,8 +30,11 @@ public: void SetError(std::string const& e); + bool DebugModeEnabled() const { return this->DebugMode; } + protected: friend class cmSearchPath; + friend class cmFindBaseDebugState; /** Used to define groups of path labels */ class PathGroup : public cmPathLabel @@ -96,6 +99,10 @@ protected: /** Compute the current default search modes based on global variables. */ void SelectDefaultSearchModes(); + /** The `InitialPass` functions of the child classes should set + this->DebugMode to the result of this. */ + bool ComputeIfDebugModeWanted(); + // Path arguments prior to path manipulation routines std::vector<std::string> UserHintsArgs; std::vector<std::string> UserGuessArgs; @@ -106,6 +113,8 @@ protected: bool CheckCommonArgument(std::string const& arg); void AddPathSuffix(std::string const& arg); + void DebugMessage(std::string const& msg) const; + bool DebugMode; bool NoDefaultPath; bool NoPackageRootPath; bool NoCMakePath; diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx index 20221b1..31f1201 100644 --- a/Source/cmFindLibraryCommand.cxx +++ b/Source/cmFindLibraryCommand.cxx @@ -12,6 +12,7 @@ #include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -29,6 +30,7 @@ cmFindLibraryCommand::cmFindLibraryCommand(cmExecutionStatus& status) // cmFindLibraryCommand bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn) { + this->DebugMode = ComputeIfDebugModeWanted(); this->VariableDocumentation = "Path to a library."; this->CMakePathName = "LIBRARY"; if (!this->ParseArguments(argsIn)) { @@ -74,15 +76,22 @@ bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn) std::string const library = this->FindLibrary(); if (!library.empty()) { // Save the value in the cache - this->Makefile->AddCacheDefinition(this->VariableName, library.c_str(), + this->Makefile->AddCacheDefinition(this->VariableName, library, this->VariableDocumentation.c_str(), cmStateEnums::FILEPATH); return true; } std::string notfound = this->VariableName + "-NOTFOUND"; - this->Makefile->AddCacheDefinition(this->VariableName, notfound.c_str(), + this->Makefile->AddCacheDefinition(this->VariableName, notfound, this->VariableDocumentation.c_str(), cmStateEnums::FILEPATH); + if (this->Required) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "Could not find " + this->VariableName + + " using the following names: " + cmJoin(this->Names, ", ")); + cmSystemTools::SetFatalErrorOccured(); + } return true; } @@ -92,6 +101,13 @@ void cmFindLibraryCommand::AddArchitecturePaths(const char* suffix) original.swap(this->SearchPaths); for (std::string const& o : original) { this->AddArchitecturePath(o, 0, suffix); + if (this->DebugMode) { + std::string msg = cmStrCat( + "find_library(", this->VariableName, ") removed original suffix ", o, + " from PATH_SUFFIXES while adding architecture paths for suffix '", + suffix, "'"); + this->DebugMessage(msg); + } } } @@ -153,11 +169,23 @@ void cmFindLibraryCommand::AddArchitecturePath( if (use_dirX) { dirX += "/"; + if (this->DebugMode) { + std::string msg = cmStrCat( + "find_library(", this->VariableName, ") added replacement path ", + dirX, " to PATH_SUFFIXES for architecture suffix '", suffix, "'"); + this->DebugMessage(msg); + } this->SearchPaths.push_back(std::move(dirX)); } if (use_dir) { this->SearchPaths.push_back(dir); + if (this->DebugMode) { + std::string msg = cmStrCat( + "find_library(", this->VariableName, ") added replacement path ", + dir, " to PATH_SUFFIXES for architecture suffix '", suffix, "'"); + this->DebugMessage(msg); + } } } } @@ -179,7 +207,7 @@ std::string cmFindLibraryCommand::FindLibrary() struct cmFindLibraryHelper { - cmFindLibraryHelper(cmMakefile* mf); + cmFindLibraryHelper(cmMakefile* mf, cmFindBase const* findBase); // Context information. cmMakefile* Makefile; @@ -198,6 +226,8 @@ struct cmFindLibraryHelper // Support for OpenBSD shared library naming: lib<name>.so.<major>.<minor> bool OpenBSD; + bool DebugMode; + // Current names under consideration. struct Name { @@ -227,10 +257,33 @@ struct cmFindLibraryHelper void SetName(std::string const& name); bool CheckDirectory(std::string const& path); bool CheckDirectoryForName(std::string const& path, Name& name); + + cmFindBaseDebugState DebugSearches; + + void DebugLibraryFailed(std::string const& name, std::string const& path) + { + if (this->DebugMode) { + auto regexName = + cmStrCat(this->PrefixRegexStr, name, this->SuffixRegexStr); + this->DebugSearches.FailedAt(path, regexName); + } + }; + + void DebugLibraryFound(std::string const& name, std::string const& path) + { + if (this->DebugMode) { + auto regexName = + cmStrCat(this->PrefixRegexStr, name, this->SuffixRegexStr); + this->DebugSearches.FoundAt(path, regexName); + } + }; }; -cmFindLibraryHelper::cmFindLibraryHelper(cmMakefile* mf) +cmFindLibraryHelper::cmFindLibraryHelper(cmMakefile* mf, + cmFindBase const* base) : Makefile(mf) + , DebugMode(base->DebugModeEnabled()) + , DebugSearches("find_library", base) { this->GG = this->Makefile->GetGlobalGenerator(); @@ -350,7 +403,12 @@ bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path, // library or an import library). if (name.TryRaw) { this->TestPath = cmStrCat(path, name.Raw); - if (cmSystemTools::FileExists(this->TestPath, true)) { + + const bool exists = cmSystemTools::FileExists(this->TestPath, true); + if (!exists) { + this->DebugLibraryFailed(name.Raw, path); + } else { + this->DebugLibraryFound(name.Raw, path); this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath); cmSystemTools::ConvertToUnixSlashes(this->BestPath); return true; @@ -376,6 +434,8 @@ bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path, if (name.Regex.find(testName)) { this->TestPath = cmStrCat(path, origName); if (!cmSystemTools::FileIsDirectory(this->TestPath)) { + this->DebugLibraryFound(name.Raw, dir); + // This is a matching file. Check if it is better than the // best name found so far. Earlier prefixes are preferred, // followed by earlier suffixes. For OpenBSD, shared library @@ -402,6 +462,12 @@ bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path, } } + if (this->BestPath.empty()) { + this->DebugLibraryFailed(name.Raw, dir); + } else { + this->DebugLibraryFound(name.Raw, this->BestPath); + } + // Use the best candidate found in this directory, if any. return !this->BestPath.empty(); } @@ -417,7 +483,7 @@ std::string cmFindLibraryCommand::FindNormalLibrary() std::string cmFindLibraryCommand::FindNormalLibraryNamesPerDir() { // Search for all names in each directory. - cmFindLibraryHelper helper(this->Makefile); + cmFindLibraryHelper helper(this->Makefile, this); for (std::string const& n : this->Names) { helper.AddName(n); } @@ -434,7 +500,7 @@ std::string cmFindLibraryCommand::FindNormalLibraryNamesPerDir() std::string cmFindLibraryCommand::FindNormalLibraryDirsPerName() { // Search the entire path for each name. - cmFindLibraryHelper helper(this->Makefile); + cmFindLibraryHelper helper(this->Makefile, this); for (std::string const& n : this->Names) { // Switch to searching for this name. helper.SetName(n); diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 2b11b62..f606002 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -160,8 +160,8 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) this->RequiredCMakeVersion = CMake_VERSION_ENCODE(v[0], v[1], v[2]); } - // Check for debug mode. - this->DebugMode = this->Makefile->IsOn("CMAKE_FIND_DEBUG_MODE"); + this->DebugMode = ComputeIfDebugModeWanted(); + this->DebugBuffer.clear(); // Lookup target architecture, if any. if (const char* arch = @@ -576,6 +576,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) } this->AppendSuccessInformation(); + return loadedPackage; } @@ -695,8 +696,23 @@ void cmFindPackageCommand::RestoreFindDefinitions() bool cmFindPackageCommand::FindModule(bool& found) { std::string module = cmStrCat("Find", this->Name, ".cmake"); + bool system = false; - std::string mfile = this->Makefile->GetModulesFile(module, system); + std::string debugBuffer = + cmStrCat("find_package considered the following paths for ", this->Name, + ".cmake\n"); + std::string mfile = this->Makefile->GetModulesFile( + module, system, this->DebugMode, debugBuffer); + if (this->DebugMode) { + if (mfile.empty()) { + debugBuffer = cmStrCat(debugBuffer, "The file was not found."); + } else { + debugBuffer = + cmStrCat(debugBuffer, "The file was found at\n ", mfile, "\n"); + } + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + } + if (!mfile.empty()) { if (system) { auto it = this->DeprecatedFindModules.find(this->Name); @@ -827,6 +843,11 @@ bool cmFindPackageCommand::HandlePackageMode( result = false; } + if (this->DebugMode) { + this->DebugMessage(this->DebugBuffer); + this->DebugBuffer.clear(); + } + // package not found if (result && !found) { // warn if package required or neither quiet nor in config mode @@ -987,6 +1008,11 @@ bool cmFindPackageCommand::FindConfig() // Look for the project's configuration file. bool found = false; + if (this->DebugMode) { + this->DebugBuffer = cmStrCat(this->DebugBuffer, + "find_package considered the following " + "locations for the Config module:\n"); + } // Search for frameworks. if (!found && (this->SearchFrameworkFirst || this->SearchFrameworkOnly)) { @@ -1013,6 +1039,16 @@ bool cmFindPackageCommand::FindConfig() found = this->FindAppBundleConfig(); } + if (this->DebugMode) { + if (found) { + this->DebugBuffer = cmStrCat( + this->DebugBuffer, "The file was found at\n ", this->FileFound, "\n"); + } else { + this->DebugBuffer = + cmStrCat(this->DebugBuffer, "The file was not found.\n"); + } + } + // Store the entry in the cache so it can be set by the user. std::string init; if (found) { @@ -1024,8 +1060,9 @@ bool cmFindPackageCommand::FindConfig() cmStrCat("The directory containing a CMake configuration file for ", this->Name, '.'); // We force the value since we do not get here if it was already set. - this->Makefile->AddCacheDefinition(this->Variable, init.c_str(), - help.c_str(), cmStateEnums::PATH, true); + this->Makefile->AddCacheDefinition(this->Variable, init, help.c_str(), + cmStateEnums::PATH, true); + return found; } @@ -1164,6 +1201,21 @@ void cmFindPackageCommand::AppendSuccessInformation() this->Makefile->FindPackageRootPathStack.pop_back(); } +inline std::size_t collectPathsForDebug(std::string& buffer, + cmSearchPath const& searchPath, + std::size_t startIndex = 0) +{ + const auto& paths = searchPath.GetPaths(); + if (paths.empty()) { + buffer += " none"; + return 0; + } + for (std::size_t i = startIndex; i < paths.size(); i++) { + buffer += " " + paths[i] + "\n"; + } + return paths.size(); +} + void cmFindPackageCommand::ComputePrefixes() { if (!this->NoDefaultPath) { @@ -1177,7 +1229,9 @@ void cmFindPackageCommand::ComputePrefixes() this->FillPrefixesCMakeEnvironment(); } } + this->FillPrefixesUserHints(); + if (!this->NoDefaultPath) { if (!this->NoSystemEnvironmentPath) { this->FillPrefixesSystemEnvironment(); @@ -1209,29 +1263,72 @@ void cmFindPackageCommand::FillPrefixesPackageRoot() paths.AddPath(path); } } + if (this->DebugMode) { + std::string debugBuffer = "<PackageName>_ROOT CMake variable " + "[CMAKE_FIND_USE_PACKAGE_ROOT_PATH].\n"; + collectPathsForDebug(debugBuffer, paths); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + } } void cmFindPackageCommand::FillPrefixesCMakeEnvironment() { cmSearchPath& paths = this->LabeledPaths[PathLabel::CMakeEnvironment]; + std::string debugBuffer; + std::size_t debugOffset = 0; // Check the environment variable with the same name as the cache // entry. paths.AddEnvPath(this->Variable); + if (this->DebugMode) { + debugBuffer = cmStrCat("Env variable ", this->Variable, + " [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].\n"); + debugOffset = collectPathsForDebug(debugBuffer, paths); + } // And now the general CMake environment variables paths.AddEnvPath("CMAKE_PREFIX_PATH"); + if (this->DebugMode) { + debugBuffer = cmStrCat(debugBuffer, + "\nCMAKE_PREFIX_PATH env variable " + "[CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].\n"); + debugOffset = collectPathsForDebug(debugBuffer, paths, debugOffset); + } + paths.AddEnvPath("CMAKE_FRAMEWORK_PATH"); paths.AddEnvPath("CMAKE_APPBUNDLE_PATH"); + if (this->DebugMode) { + debugBuffer = + cmStrCat(debugBuffer, + "\nCMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH env " + "variables [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].\n"); + collectPathsForDebug(debugBuffer, paths, debugOffset); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + } } void cmFindPackageCommand::FillPrefixesCMakeVariable() { cmSearchPath& paths = this->LabeledPaths[PathLabel::CMake]; + std::string debugBuffer; + std::size_t debugOffset = 0; paths.AddCMakePath("CMAKE_PREFIX_PATH"); + if (this->DebugMode) { + debugBuffer = "CMAKE_PREFIX_PATH variable [CMAKE_FIND_USE_CMAKE_PATH].\n"; + debugOffset = collectPathsForDebug(debugBuffer, paths); + } + paths.AddCMakePath("CMAKE_FRAMEWORK_PATH"); paths.AddCMakePath("CMAKE_APPBUNDLE_PATH"); + if (this->DebugMode) { + debugBuffer = + cmStrCat(debugBuffer, + "\nCMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH variables " + "[CMAKE_FIND_USE_CMAKE_PATH].\n"); + collectPathsForDebug(debugBuffer, paths, debugOffset); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + } } void cmFindPackageCommand::FillPrefixesSystemEnvironment() @@ -1251,6 +1348,12 @@ void cmFindPackageCommand::FillPrefixesSystemEnvironment() paths.AddPath(i); } } + if (this->DebugMode) { + std::string debugBuffer = "Standard system environment variables " + "[CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH].\n"; + collectPathsForDebug(debugBuffer, paths); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + } } void cmFindPackageCommand::FillPrefixesUserRegistry() @@ -1274,6 +1377,13 @@ void cmFindPackageCommand::FillPrefixesUserRegistry() this->LabeledPaths[PathLabel::UserRegistry]); } #endif + if (this->DebugMode) { + std::string debugBuffer = + "CMake User Package Registry [CMAKE_FIND_USE_PACKAGE_REGISTRY].\n"; + collectPathsForDebug(debugBuffer, + this->LabeledPaths[PathLabel::UserRegistry]); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + } } void cmFindPackageCommand::FillPrefixesSystemRegistry() @@ -1285,6 +1395,15 @@ void cmFindPackageCommand::FillPrefixesSystemRegistry() #if defined(_WIN32) && !defined(__CYGWIN__) this->LoadPackageRegistryWinSystem(); #endif + + if (this->DebugMode) { + std::string debugBuffer = + "CMake System Package Registry " + "[CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY].\n"; + collectPathsForDebug(debugBuffer, + this->LabeledPaths[PathLabel::SystemRegistry]); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + } } #if defined(_WIN32) && !defined(__CYGWIN__) @@ -1457,6 +1576,13 @@ void cmFindPackageCommand::FillPrefixesCMakeSystemVariable() paths.AddCMakePath("CMAKE_SYSTEM_PREFIX_PATH"); paths.AddCMakePath("CMAKE_SYSTEM_FRAMEWORK_PATH"); paths.AddCMakePath("CMAKE_SYSTEM_APPBUNDLE_PATH"); + + if (this->DebugMode) { + std::string debugBuffer = "CMake variables defined in the Platform file " + "[CMAKE_FIND_USE_CMAKE_SYSTEM_PATH].\n"; + collectPathsForDebug(debugBuffer, paths); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + } } void cmFindPackageCommand::FillPrefixesUserGuess() @@ -1466,6 +1592,12 @@ void cmFindPackageCommand::FillPrefixesUserGuess() for (std::string const& p : this->UserGuessArgs) { paths.AddUserPath(p); } + if (this->DebugMode) { + std::string debugBuffer = + "Paths specified by the find_package PATHS option.\n"; + collectPathsForDebug(debugBuffer, paths); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + } } void cmFindPackageCommand::FillPrefixesUserHints() @@ -1475,6 +1607,12 @@ void cmFindPackageCommand::FillPrefixesUserHints() for (std::string const& p : this->UserHintsArgs) { paths.AddUserPath(p); } + if (this->DebugMode) { + std::string debugBuffer = + "Paths specified by the find_package HINTS option.\n"; + collectPathsForDebug(debugBuffer, paths); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + } } bool cmFindPackageCommand::SearchDirectory(std::string const& dir) @@ -1519,7 +1657,7 @@ bool cmFindPackageCommand::FindConfigFile(std::string const& dir, for (std::string const& c : this->Configs) { file = cmStrCat(dir, '/', c); if (this->DebugMode) { - fprintf(stderr, "Checking file [%s]\n", file.c_str()); + this->DebugBuffer = cmStrCat(this->DebugBuffer, " ", file, "\n"); } if (cmSystemTools::FileExists(file, true) && this->CheckVersion(file)) { // Allow resolving symlinks when the config file is found through a link @@ -2032,9 +2170,6 @@ private: bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) { assert(!prefix_in.empty() && prefix_in.back() == '/'); - if (this->DebugMode) { - fprintf(stderr, "Checking prefix [%s]\n", prefix_in.c_str()); - } // Skip this if the prefix does not exist. if (!cmSystemTools::FileIsDirectory(prefix_in)) { @@ -2188,9 +2323,6 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in) { assert(!prefix_in.empty() && prefix_in.back() == '/'); - if (this->DebugMode) { - fprintf(stderr, "Checking framework prefix [%s]\n", prefix_in.c_str()); - } // Strip the trailing slash because the path generator is about to // add one. @@ -2249,9 +2381,6 @@ bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in) bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in) { assert(!prefix_in.empty() && prefix_in.back() == '/'); - if (this->DebugMode) { - fprintf(stderr, "Checking bundle prefix [%s]\n", prefix_in.c_str()); - } // Strip the trailing slash because the path generator is about to // add one. diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h index 85fe7b6..ae9ade7 100644 --- a/Source/cmFindPackageCommand.h +++ b/Source/cmFindPackageCommand.h @@ -174,7 +174,6 @@ private: bool UseFindModules; bool NoUserRegistry; bool NoSystemRegistry; - bool DebugMode; bool UseLib32Paths; bool UseLib64Paths; bool UseLibx32Paths; @@ -184,6 +183,7 @@ private: std::vector<std::string> Names; std::vector<std::string> Configs; std::set<std::string> IgnoredPaths; + std::string DebugBuffer; /*! the selected sortOrder (None by default)*/ SortOrderType SortOrder; diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx index f5e2631..4bab469 100644 --- a/Source/cmFindPathCommand.cxx +++ b/Source/cmFindPathCommand.cxx @@ -5,6 +5,7 @@ #include "cmsys/Glob.hxx" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -21,6 +22,7 @@ cmFindPathCommand::cmFindPathCommand(cmExecutionStatus& status) // cmFindPathCommand bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn) { + this->DebugMode = ComputeIfDebugModeWanted(); this->VariableDocumentation = "Path to a file."; this->CMakePathName = "INCLUDE"; if (!this->ParseArguments(argsIn)) { @@ -42,29 +44,39 @@ bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn) std::string result = this->FindHeader(); if (!result.empty()) { this->Makefile->AddCacheDefinition( - this->VariableName, result.c_str(), this->VariableDocumentation.c_str(), + this->VariableName, result, this->VariableDocumentation.c_str(), (this->IncludeFileInPath) ? cmStateEnums::FILEPATH : cmStateEnums::PATH); return true; } this->Makefile->AddCacheDefinition( - this->VariableName, (this->VariableName + "-NOTFOUND").c_str(), + this->VariableName, this->VariableName + "-NOTFOUND", this->VariableDocumentation.c_str(), (this->IncludeFileInPath) ? cmStateEnums::FILEPATH : cmStateEnums::PATH); + if (this->Required) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "Could not find " + this->VariableName + + " using the following files: " + cmJoin(this->Names, ", ")); + cmSystemTools::SetFatalErrorOccured(); + } return true; } std::string cmFindPathCommand::FindHeader() { + std::string debug_name = this->IncludeFileInPath ? "find_file" : "find_path"; + cmFindBaseDebugState debug(debug_name, this); std::string header; if (this->SearchFrameworkFirst || this->SearchFrameworkOnly) { - header = this->FindFrameworkHeader(); + header = this->FindFrameworkHeader(debug); } if (header.empty() && !this->SearchFrameworkOnly) { - header = this->FindNormalHeader(); + header = this->FindNormalHeader(debug); } if (header.empty() && this->SearchFrameworkLast) { - header = this->FindFrameworkHeader(); + header = this->FindFrameworkHeader(debug); } + return header; } @@ -116,28 +128,31 @@ std::string cmFindPathCommand::FindHeaderInFramework(std::string const& file, return ""; } -std::string cmFindPathCommand::FindNormalHeader() +std::string cmFindPathCommand::FindNormalHeader(cmFindBaseDebugState& debug) { std::string tryPath; for (std::string const& n : this->Names) { for (std::string const& sp : this->SearchPaths) { tryPath = cmStrCat(sp, n); if (cmSystemTools::FileExists(tryPath)) { + debug.FoundAt(tryPath); if (this->IncludeFileInPath) { return tryPath; } return sp; } + debug.FailedAt(tryPath); } } return ""; } -std::string cmFindPathCommand::FindFrameworkHeader() +std::string cmFindPathCommand::FindFrameworkHeader(cmFindBaseDebugState& debug) { for (std::string const& n : this->Names) { for (std::string const& sp : this->SearchPaths) { std::string fwPath = this->FindHeaderInFramework(n, sp); + fwPath.empty() ? debug.FailedAt(fwPath) : debug.FoundAt(fwPath); if (!fwPath.empty()) { return fwPath; } diff --git a/Source/cmFindPathCommand.h b/Source/cmFindPathCommand.h index 8d1ea8b..18bfb7d 100644 --- a/Source/cmFindPathCommand.h +++ b/Source/cmFindPathCommand.h @@ -32,8 +32,8 @@ private: std::string FindHeaderInFramework(std::string const& file, std::string const& dir); std::string FindHeader(); - std::string FindNormalHeader(); - std::string FindFrameworkHeader(); + std::string FindNormalHeader(cmFindBaseDebugState& debug); + std::string FindFrameworkHeader(cmFindBaseDebugState& debug); }; bool cmFindPath(std::vector<std::string> const& args, diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx index e0a3fbf..4b88bea 100644 --- a/Source/cmFindProgramCommand.cxx +++ b/Source/cmFindProgramCommand.cxx @@ -3,6 +3,7 @@ #include "cmFindProgramCommand.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -15,7 +16,9 @@ class cmExecutionStatus; struct cmFindProgramHelper { - cmFindProgramHelper() + cmFindProgramHelper(cmMakefile* makefile, cmFindBase const* base) + : DebugSearches("find_program", base) + , Makefile(makefile) { #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) // Consider platform-specific extensions. @@ -41,6 +44,10 @@ struct cmFindProgramHelper // Current full path under consideration. std::string TestPath; + // Debug state + cmFindBaseDebugState DebugSearches; + cmMakefile* Makefile; + void AddName(std::string const& name) { this->Names.push_back(name); } void SetName(std::string const& name) { @@ -78,8 +85,10 @@ struct cmFindProgramHelper this->TestNameExt = cmStrCat(name, ext); this->TestPath = cmSystemTools::CollapseFullPath(this->TestNameExt, path); - - if (cmSystemTools::FileExists(this->TestPath, true)) { + bool exists = cmSystemTools::FileExists(this->TestPath, true); + exists ? this->DebugSearches.FoundAt(this->TestPath) + : this->DebugSearches.FailedAt(this->TestPath); + if (exists) { this->BestPath = this->TestPath; return true; } @@ -97,6 +106,7 @@ cmFindProgramCommand::cmFindProgramCommand(cmExecutionStatus& status) // cmFindProgramCommand bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn) { + this->DebugMode = ComputeIfDebugModeWanted(); this->VariableDocumentation = "Path to a program."; this->CMakePathName = "PROGRAM"; // call cmFindBase::ParseArguments @@ -118,15 +128,22 @@ bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn) std::string const result = FindProgram(); if (!result.empty()) { // Save the value in the cache - this->Makefile->AddCacheDefinition(this->VariableName, result.c_str(), + this->Makefile->AddCacheDefinition(this->VariableName, result, this->VariableDocumentation.c_str(), cmStateEnums::FILEPATH); return true; } this->Makefile->AddCacheDefinition( - this->VariableName, (this->VariableName + "-NOTFOUND").c_str(), + this->VariableName, this->VariableName + "-NOTFOUND", this->VariableDocumentation.c_str(), cmStateEnums::FILEPATH); + if (this->Required) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "Could not find " + this->VariableName + + " using the following names: " + cmJoin(this->Names, ", ")); + cmSystemTools::SetFatalErrorOccured(); + } return true; } @@ -158,7 +175,7 @@ std::string cmFindProgramCommand::FindNormalProgram() std::string cmFindProgramCommand::FindNormalProgramNamesPerDir() { // Search for all names in each directory. - cmFindProgramHelper helper; + cmFindProgramHelper helper(this->Makefile, this); for (std::string const& n : this->Names) { helper.AddName(n); } @@ -181,7 +198,7 @@ std::string cmFindProgramCommand::FindNormalProgramNamesPerDir() std::string cmFindProgramCommand::FindNormalProgramDirsPerName() { // Search the entire path for each name. - cmFindProgramHelper helper; + cmFindProgramHelper helper(this->Makefile, this); for (std::string const& n : this->Names) { // Switch to searching for this name. helper.SetName(n); diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index 44392ba..0546186 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -2,8 +2,18 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmForEachCommand.h" -#include <cstdio> +#include <algorithm> +#include <cassert> +#include <cstddef> +// NOTE The declaration of `std::abs` has moved to `cmath` since C++17 +// See https://en.cppreference.com/w/cpp/numeric/math/abs +// ALERT But IWYU used to lint `#include`s do not "understand" +// conditional compilation (i.e. `#if __cplusplus >= 201703L`) #include <cstdlib> +#include <iterator> +#include <map> +#include <sstream> +#include <stdexcept> #include <utility> #include <cm/memory> @@ -21,12 +31,10 @@ #include "cmSystemTools.h" namespace { -bool HandleInMode(std::vector<std::string> const& args, cmMakefile& makefile); - class cmForEachFunctionBlocker : public cmFunctionBlocker { public: - cmForEachFunctionBlocker(cmMakefile* mf); + explicit cmForEachFunctionBlocker(cmMakefile* mf); ~cmForEachFunctionBlocker() override; cm::string_view StartCommandName() const override { return "foreach"_s; } @@ -38,10 +46,33 @@ public: bool Replay(std::vector<cmListFileFunction> functions, cmExecutionStatus& inStatus) override; + void SetIterationVarsCount(const std::size_t varsCount) + { + this->IterationVarsCount = varsCount; + } + void SetZipLists() { this->ZipLists = true; } + std::vector<std::string> Args; private: + struct InvokeResult + { + bool Restore; + bool Break; + }; + + bool ReplayItems(std::vector<cmListFileFunction> const& functions, + cmExecutionStatus& inStatus); + + bool ReplayZipLists(std::vector<cmListFileFunction> const& functions, + cmExecutionStatus& inStatus); + + InvokeResult invoke(std::vector<cmListFileFunction> const& functions, + cmExecutionStatus& inStatus, cmMakefile& mf); + cmMakefile* Makefile; + std::size_t IterationVarsCount = 0u; + bool ZipLists = false; }; cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf) @@ -60,53 +91,288 @@ bool cmForEachFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, { std::vector<std::string> expandedArguments; mf.ExpandArguments(lff.Arguments, expandedArguments); - return expandedArguments.empty() || expandedArguments[0] == this->Args[0]; + return expandedArguments.empty() || + expandedArguments.front() == this->Args.front(); } bool cmForEachFunctionBlocker::Replay( std::vector<cmListFileFunction> functions, cmExecutionStatus& inStatus) { - cmMakefile& mf = inStatus.GetMakefile(); - // at end of for each execute recorded commands + return this->ZipLists ? this->ReplayZipLists(functions, inStatus) + : this->ReplayItems(functions, inStatus); +} + +bool cmForEachFunctionBlocker::ReplayItems( + std::vector<cmListFileFunction> const& functions, + cmExecutionStatus& inStatus) +{ + assert("Unexpected number of iteration variables" && + this->IterationVarsCount == 1); + + auto& mf = inStatus.GetMakefile(); + + // At end of for each execute recorded commands // store the old value std::string oldDef; - if (mf.GetDefinition(this->Args[0])) { - oldDef = mf.GetDefinition(this->Args[0]); + if (mf.GetDefinition(this->Args.front())) { + oldDef = mf.GetDefinition(this->Args.front()); } + auto restore = false; for (std::string const& arg : cmMakeRange(this->Args).advance(1)) { - // set the variable to the loop value - mf.AddDefinition(this->Args[0], arg); + // Set the variable to the loop value + mf.AddDefinition(this->Args.front(), arg); + // Invoke all the functions that were collected in the block. + auto r = this->invoke(functions, inStatus, mf); + restore = r.Restore; + if (r.Break) { + break; + } + } + + if (restore) { + // restore the variable to its prior value + mf.AddDefinition(this->Args.front(), oldDef); + } + return true; +} + +bool cmForEachFunctionBlocker::ReplayZipLists( + std::vector<cmListFileFunction> const& functions, + cmExecutionStatus& inStatus) +{ + assert("Unexpected number of iteration variables" && + this->IterationVarsCount >= 1); + + auto& mf = inStatus.GetMakefile(); + + // Expand the list of list-variables into a list of lists of strings + std::vector<std::vector<std::string>> values; + values.reserve(this->Args.size() - this->IterationVarsCount); + // Also track the longest list size + std::size_t maxItems = 0u; + for (auto const& var : + cmMakeRange(this->Args).advance(this->IterationVarsCount)) { + std::vector<std::string> items; + auto const& value = mf.GetSafeDefinition(var); + if (!value.empty()) { + cmExpandList(value, items, true); + } + maxItems = std::max(maxItems, items.size()); + values.emplace_back(std::move(items)); + } + + // Form the list of iteration variables + std::vector<std::string> iterationVars; + if (this->IterationVarsCount > 1) { + // If multiple iteration variables has given, + // just copy them to the `iterationVars` list. + iterationVars.reserve(values.size()); + std::copy(this->Args.begin(), + this->Args.begin() + this->IterationVarsCount, + std::back_inserter(iterationVars)); + } else { + // In case of the only iteration variable, + // generate names as `var_name_N`, + // where `N` is the count of lists to zip + iterationVars.resize(values.size()); + const auto iter_var_prefix = this->Args.front() + "_"; + auto i = 0u; + std::generate( + iterationVars.begin(), iterationVars.end(), + [&]() -> std::string { return iter_var_prefix + std::to_string(i++); }); + } + assert("Sanity check" && iterationVars.size() == values.size()); + + // Store old values for iteration variables + std::map<std::string, std::string> oldDefs; + for (auto i = 0u; i < values.size(); ++i) { + if (mf.GetDefinition(iterationVars[i])) { + oldDefs.emplace(iterationVars[i], mf.GetDefinition(iterationVars[i])); + } + } + + // Form a vector of current positions in all lists (Ok, vectors) of values + std::vector<decltype(values)::value_type::iterator> positions; + positions.reserve(values.size()); + std::transform( + values.begin(), values.end(), std::back_inserter(positions), + // Set the initial position to the beginning of every list + [](decltype(values)::value_type& list) { return list.begin(); }); + assert("Sanity check" && positions.size() == values.size()); + + auto restore = false; + // Iterate over all the lists simulateneously + for (auto i = 0u; i < maxItems; ++i) { + // Declare iteration variables + for (auto j = 0u; j < values.size(); ++j) { + // Define (or not) the iteration variable if the current position + // still not at the end... + if (positions[j] != values[j].end()) { + mf.AddDefinition(iterationVars[j], *positions[j]); + ++positions[j]; + } else { + mf.RemoveDefinition(iterationVars[j]); + } + } // Invoke all the functions that were collected in the block. - for (cmListFileFunction const& func : functions) { - cmExecutionStatus status(mf); - mf.ExecuteCommand(func, status); - if (status.GetReturnInvoked()) { - inStatus.SetReturnInvoked(); - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); + auto r = this->invoke(functions, inStatus, mf); + restore = r.Restore; + if (r.Break) { + break; + } + } + + // Restore the variables to its prior value + if (restore) { + for (auto const& p : oldDefs) { + mf.AddDefinition(p.first, p.second); + } + } + return true; +} + +auto cmForEachFunctionBlocker::invoke( + std::vector<cmListFileFunction> const& functions, + cmExecutionStatus& inStatus, cmMakefile& mf) -> InvokeResult +{ + InvokeResult result = { true, false }; + // Invoke all the functions that were collected in the block. + for (cmListFileFunction const& func : functions) { + cmExecutionStatus status(mf); + mf.ExecuteCommand(func, status); + if (status.GetReturnInvoked()) { + inStatus.SetReturnInvoked(); + result.Break = true; + break; + } + if (status.GetBreakInvoked()) { + result.Break = true; + break; + } + if (status.GetContinueInvoked()) { + break; + } + if (cmSystemTools::GetFatalErrorOccured()) { + result.Restore = false; + result.Break = true; + break; + } + } + return result; +} + +bool HandleInMode(std::vector<std::string> const& args, + std::vector<std::string>::const_iterator kwInIter, + cmMakefile& makefile) +{ + assert("A valid iterator expected" && kwInIter != args.end()); + + auto fb = cm::make_unique<cmForEachFunctionBlocker>(&makefile); + + // Copy iteration variable names first + std::copy(args.begin(), kwInIter, std::back_inserter(fb->Args)); + // Remember the count of given iteration variable names + const auto varsCount = fb->Args.size(); + fb->SetIterationVarsCount(varsCount); + + enum Doing + { + DoingNone, + DoingLists, + DoingItems, + DoingZipLists + }; + Doing doing = DoingNone; + // Iterate over arguments past the "IN" keyword + for (std::string const& arg : cmMakeRange(++kwInIter, args.end())) { + if (arg == "LISTS") { + if (doing == DoingZipLists) { + makefile.IssueMessage(MessageType::FATAL_ERROR, + "ZIP_LISTS can not be used with LISTS or ITEMS"); + return true; + } + if (varsCount != 1u) { + makefile.IssueMessage( + MessageType::FATAL_ERROR, + "ITEMS or LISTS require exactly one iteration variable"); return true; } - if (status.GetBreakInvoked()) { - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); + doing = DoingLists; + + } else if (arg == "ITEMS") { + if (doing == DoingZipLists) { + makefile.IssueMessage(MessageType::FATAL_ERROR, + "ZIP_LISTS can not be used with LISTS or ITEMS"); return true; } - if (status.GetContinueInvoked()) { - break; + if (varsCount != 1u) { + makefile.IssueMessage( + MessageType::FATAL_ERROR, + "ITEMS or LISTS require exactly one iteration variable"); + return true; } - if (cmSystemTools::GetFatalErrorOccured()) { + doing = DoingItems; + + } else if (arg == "ZIP_LISTS") { + if (doing != DoingNone) { + makefile.IssueMessage(MessageType::FATAL_ERROR, + "ZIP_LISTS can not be used with LISTS or ITEMS"); return true; } + doing = DoingZipLists; + fb->SetZipLists(); + + } else if (doing == DoingLists) { + auto const& value = makefile.GetSafeDefinition(arg); + if (!value.empty()) { + cmExpandList(value, fb->Args, true); + } + + } else if (doing == DoingItems || doing == DoingZipLists) { + fb->Args.push_back(arg); + + } else { + makefile.IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("Unknown argument:\n", " ", arg, "\n")); + return true; } } - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); + // If `ZIP_LISTS` given and variables count more than 1, + // make sure the given lists count matches variables... + if (doing == DoingZipLists && varsCount > 1u && + (2u * varsCount) != fb->Args.size()) { + makefile.IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Expected ", std::to_string(varsCount), + " list variables, but given ", + std::to_string(fb->Args.size() - varsCount))); + return true; + } + + makefile.AddFunctionBlocker(std::move(fb)); + return true; } + +bool TryParseInteger(cmExecutionStatus& status, const std::string& str, int& i) +{ + try { + i = std::stoi(str); + } catch (std::invalid_argument&) { + std::ostringstream e; + e << "Invalid integer: '" << str << "'"; + status.SetError(e.str()); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + return true; } +} // anonymous namespace + bool cmForEachCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -114,8 +380,9 @@ bool cmForEachCommand(std::vector<std::string> const& args, status.SetError("called with incorrect number of arguments"); return false; } - if (args.size() > 1 && args[1] == "IN") { - return HandleInMode(args, status.GetMakefile()); + auto kwInIter = std::find(args.begin(), args.end(), "IN"); + if (kwInIter != args.end()) { + return HandleInMode(args, kwInIter, status.GetMakefile()); } // create a function blocker @@ -126,16 +393,28 @@ bool cmForEachCommand(std::vector<std::string> const& args, int stop = 0; int step = 0; if (args.size() == 3) { - stop = atoi(args[2].c_str()); + if (!TryParseInteger(status, args[2], stop)) { + return false; + } } if (args.size() == 4) { - start = atoi(args[2].c_str()); - stop = atoi(args[3].c_str()); + if (!TryParseInteger(status, args[2], start)) { + return false; + } + if (!TryParseInteger(status, args[3], stop)) { + return false; + } } if (args.size() == 5) { - start = atoi(args[2].c_str()); - stop = atoi(args[3].c_str()); - step = atoi(args[4].c_str()); + if (!TryParseInteger(status, args[2], start)) { + return false; + } + if (!TryParseInteger(status, args[3], stop)) { + return false; + } + if (!TryParseInteger(status, args[4], step)) { + return false; + } } if (step == 0) { if (start > stop) { @@ -149,69 +428,36 @@ bool cmForEachCommand(std::vector<std::string> const& args, status.SetError( cmStrCat("called with incorrect range specification: start ", start, ", stop ", stop, ", step ", step)); + cmSystemTools::SetFatalErrorOccured(); return false; } - std::vector<std::string> range; - char buffer[100]; - range.push_back(args[0]); - int cc; - for (cc = start;; cc += step) { - if ((step > 0 && cc > stop) || (step < 0 && cc < stop)) { - break; - } - sprintf(buffer, "%d", cc); - range.emplace_back(buffer); - if (cc == stop) { - break; - } - } - fb->Args = range; + + // Calculate expected iterations count and reserve enough space + // in the `fb->Args` vector. The first item is the iteration variable + // name... + const std::size_t iter_cnt = 2u + + int(start < stop) * (stop - start) / std::abs(step) + + int(start > stop) * (start - stop) / std::abs(step); + fb->Args.resize(iter_cnt); + fb->Args.front() = args.front(); + auto cc = start; + auto generator = [&cc, step]() -> std::string { + auto result = std::to_string(cc); + cc += step; + return result; + }; + // Fill the `range` vector w/ generated string values + // (starting from 2nd position) + std::generate(++fb->Args.begin(), fb->Args.end(), generator); } else { fb->Args = args; } } else { fb->Args = args; } - status.GetMakefile().AddFunctionBlocker(std::move(fb)); - - return true; -} - -namespace { -bool HandleInMode(std::vector<std::string> const& args, cmMakefile& makefile) -{ - auto fb = cm::make_unique<cmForEachFunctionBlocker>(&makefile); - fb->Args.push_back(args[0]); - - enum Doing - { - DoingNone, - DoingLists, - DoingItems - }; - Doing doing = DoingNone; - for (unsigned int i = 2; i < args.size(); ++i) { - if (doing == DoingItems) { - fb->Args.push_back(args[i]); - } else if (args[i] == "LISTS") { - doing = DoingLists; - } else if (args[i] == "ITEMS") { - doing = DoingItems; - } else if (doing == DoingLists) { - const char* value = makefile.GetDefinition(args[i]); - if (value && *value) { - cmExpandList(value, fb->Args, true); - } - } else { - makefile.IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("Unknown argument:\n", " ", args[i], "\n")); - return true; - } - } - makefile.AddFunctionBlocker(std::move(fb)); + fb->SetIterationVarsCount(1u); + status.GetMakefile().AddFunctionBlocker(std::move(fb)); return true; } -} diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index b3ddfe0..a4c9072 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -2,15 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmFunctionCommand.h" -#include <sstream> #include <utility> #include <cm/memory> #include <cm/string_view> +#include <cmext/algorithm> #include "cm_static_string_view.hxx" -#include "cmAlgorithms.h" #include "cmExecutionStatus.h" #include "cmFunctionBlocker.h" #include "cmListFileCache.h" @@ -19,8 +18,20 @@ #include "cmRange.h" #include "cmState.h" #include "cmStringAlgorithms.h" +#include "cmSystemTools.h" namespace { +std::string const ARGC = "ARGC"; +std::string const ARGN = "ARGN"; +std::string const ARGV = "ARGV"; +std::string const CMAKE_CURRENT_FUNCTION = "CMAKE_CURRENT_FUNCTION"; +std::string const CMAKE_CURRENT_FUNCTION_LIST_FILE = + "CMAKE_CURRENT_FUNCTION_LIST_FILE"; +std::string const CMAKE_CURRENT_FUNCTION_LIST_DIR = + "CMAKE_CURRENT_FUNCTION_LIST_DIR"; +std::string const CMAKE_CURRENT_FUNCTION_LIST_LINE = + "CMAKE_CURRENT_FUNCTION_LIST_LINE"; + // define the class for function commands class cmFunctionHelperCommand { @@ -36,8 +47,8 @@ public: std::vector<cmListFileFunction> Functions; cmPolicies::PolicyMap Policies; std::string FilePath; + long Line; }; -} bool cmFunctionHelperCommand::operator()( std::vector<cmListFileArgument> const& args, @@ -52,9 +63,9 @@ bool cmFunctionHelperCommand::operator()( // make sure the number of arguments passed is at least the number // required by the signature if (expandedArgs.size() < this->Args.size() - 1) { - std::string errorMsg = cmStrCat( + auto const errorMsg = cmStrCat( "Function invoked with incorrect arguments for function named: ", - this->Args[0]); + this->Args.front()); inStatus.SetError(errorMsg); return false; } @@ -63,30 +74,40 @@ bool cmFunctionHelperCommand::operator()( this->Policies); // set the value of argc - makefile.AddDefinition("ARGC", std::to_string(expandedArgs.size())); - makefile.MarkVariableAsUsed("ARGC"); + makefile.AddDefinition(ARGC, std::to_string(expandedArgs.size())); + makefile.MarkVariableAsUsed(ARGC); // set the values for ARGV0 ARGV1 ... - for (unsigned int t = 0; t < expandedArgs.size(); ++t) { - std::ostringstream tmpStream; - tmpStream << "ARGV" << t; - makefile.AddDefinition(tmpStream.str(), expandedArgs[t]); - makefile.MarkVariableAsUsed(tmpStream.str()); + for (auto t = 0u; t < expandedArgs.size(); ++t) { + auto const value = cmStrCat(ARGV, std::to_string(t)); + makefile.AddDefinition(value, expandedArgs[t]); + makefile.MarkVariableAsUsed(value); } // define the formal arguments - for (unsigned int j = 1; j < this->Args.size(); ++j) { + for (auto j = 1u; j < this->Args.size(); ++j) { makefile.AddDefinition(this->Args[j], expandedArgs[j - 1]); } // define ARGV and ARGN - std::string argvDef = cmJoin(expandedArgs, ";"); - auto eit = expandedArgs.begin() + (this->Args.size() - 1); - std::string argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";"); - makefile.AddDefinition("ARGV", argvDef); - makefile.MarkVariableAsUsed("ARGV"); - makefile.AddDefinition("ARGN", argnDef); - makefile.MarkVariableAsUsed("ARGN"); + auto const argvDef = cmJoin(expandedArgs, ";"); + auto const eit = expandedArgs.begin() + (this->Args.size() - 1); + auto const argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";"); + makefile.AddDefinition(ARGV, argvDef); + makefile.MarkVariableAsUsed(ARGV); + makefile.AddDefinition(ARGN, argnDef); + makefile.MarkVariableAsUsed(ARGN); + + makefile.AddDefinition(CMAKE_CURRENT_FUNCTION, this->Args.front()); + makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION); + makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_FILE, this->FilePath); + makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_FILE); + makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_DIR, + cmSystemTools::GetFilenamePath(this->FilePath)); + makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_DIR); + makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_LINE, + std::to_string(this->Line)); + makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_LINE); // Invoke all the functions that were collected in the block. // for each function @@ -100,7 +121,7 @@ bool cmFunctionHelperCommand::operator()( return false; } if (status.GetReturnInvoked()) { - return true; + break; } } @@ -129,7 +150,8 @@ bool cmFunctionFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, std::vector<std::string> expandedArguments; mf.ExpandArguments(lff.Arguments, expandedArguments, this->GetStartingContext().FilePath.c_str()); - return expandedArguments.empty() || expandedArguments[0] == this->Args[0]; + return expandedArguments.empty() || + expandedArguments.front() == this->Args.front(); } bool cmFunctionFunctionBlocker::Replay( @@ -141,11 +163,14 @@ bool cmFunctionFunctionBlocker::Replay( f.Args = this->Args; f.Functions = std::move(functions); f.FilePath = this->GetStartingContext().FilePath; + f.Line = this->GetStartingContext().Line; mf.RecordPolicies(f.Policies); - mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); + mf.GetState()->AddScriptedCommand(this->Args.front(), std::move(f)); return true; } +} // anonymous namespace + bool cmFunctionCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -155,10 +180,9 @@ bool cmFunctionCommand(std::vector<std::string> const& args, } // create a function blocker - { - auto fb = cm::make_unique<cmFunctionFunctionBlocker>(); - cmAppend(fb->Args, args); - status.GetMakefile().AddFunctionBlocker(std::move(fb)); - } + auto fb = cm::make_unique<cmFunctionFunctionBlocker>(); + cm::append(fb->Args, args); + status.GetMakefile().AddFunctionBlocker(std::move(fb)); + return true; } diff --git a/Source/cmGccDepfileLexerHelper.cxx b/Source/cmGccDepfileLexerHelper.cxx new file mode 100644 index 0000000..957896f --- /dev/null +++ b/Source/cmGccDepfileLexerHelper.cxx @@ -0,0 +1,126 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmGccDepfileLexerHelper.h" + +#include <cstdio> +#include <memory> +#include <string> +#include <vector> + +#include "cmGccDepfileReaderTypes.h" + +#include "LexerParser/cmGccDepfileLexer.h" + +#ifdef _WIN32 +# include "cmsys/Encoding.h" +#endif + +bool cmGccDepfileLexerHelper::readFile(const char* filePath) +{ +#ifdef _WIN32 + wchar_t* wpath = cmsysEncoding_DupToWide(filePath); + FILE* file = _wfopen(wpath, L"rb"); + free(wpath); +#else + FILE* file = fopen(filePath, "r"); +#endif + if (!file) { + return false; + } + newEntry(); + yyscan_t scanner; + cmGccDepfile_yylex_init(&scanner); + cmGccDepfile_yyset_extra(this, scanner); + cmGccDepfile_yyrestart(file, scanner); + cmGccDepfile_yylex(scanner); + cmGccDepfile_yylex_destroy(scanner); + sanitizeContent(); + fclose(file); + return true; +} + +void cmGccDepfileLexerHelper::newEntry() +{ + this->HelperState = State::Rule; + this->Content.emplace_back(); + newRule(); +} + +void cmGccDepfileLexerHelper::newRule() +{ + auto& entry = this->Content.back(); + if (entry.rules.empty() || !entry.rules.back().empty()) { + entry.rules.emplace_back(); + } +} + +void cmGccDepfileLexerHelper::newDependency() +{ + // printf("NEW DEP\n"); + this->HelperState = State::Dependency; + if (this->Content.back().paths.empty() || + !this->Content.back().paths.back().empty()) { + this->Content.back().paths.emplace_back(); + } +} + +void cmGccDepfileLexerHelper::newRuleOrDependency() +{ + if (this->HelperState == State::Rule) { + newRule(); + } else { + newDependency(); + } +} + +void cmGccDepfileLexerHelper::addToCurrentPath(const char* s) +{ + if (this->Content.empty()) { + return; + } + cmGccStyleDependency* dep = &this->Content.back(); + std::string* dst = nullptr; + switch (this->HelperState) { + case State::Rule: { + if (dep->rules.empty()) { + return; + } + dst = &dep->rules.back(); + } break; + case State::Dependency: { + if (dep->paths.empty()) { + return; + } + dst = &dep->paths.back(); + } break; + } + dst->append(s); +} + +void cmGccDepfileLexerHelper::sanitizeContent() +{ + for (auto it = this->Content.begin(); it != this->Content.end();) { + // Remove empty rules + for (auto rit = it->rules.begin(); rit != it->rules.end();) { + if (rit->empty()) { + rit = it->rules.erase(rit); + } else { + ++rit; + } + } + // Remove the entry if rules are empty + if (it->rules.empty()) { + it = this->Content.erase(it); + } else { + // Remove empty paths + for (auto pit = it->paths.begin(); pit != it->paths.end();) { + if (pit->empty()) { + pit = it->paths.erase(pit); + } else { + ++pit; + } + } + ++it; + } + } +} diff --git a/Source/cmGccDepfileLexerHelper.h b/Source/cmGccDepfileLexerHelper.h new file mode 100644 index 0000000..e6b2fcf --- /dev/null +++ b/Source/cmGccDepfileLexerHelper.h @@ -0,0 +1,40 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmGccDepfileLexerHelper_h +#define cmGccDepfileLexerHelper_h + +#include <utility> + +#include <cmGccDepfileReaderTypes.h> + +class cmGccDepfileLexerHelper +{ +public: + cmGccDepfileLexerHelper() = default; + + bool readFile(const char* filePath); + cmGccDepfileContent extractContent() && { return std::move(this->Content); } + + // Functions called by the lexer + void newEntry(); + void newRule(); + void newDependency(); + void newRuleOrDependency(); + void addToCurrentPath(const char* s); + +private: + void sanitizeContent(); + + cmGccDepfileContent Content; + + enum class State + { + Rule, + Dependency + }; + State HelperState = State::Rule; +}; + +#define YY_EXTRA_TYPE cmGccDepfileLexerHelper* + +#endif diff --git a/Source/cmGccDepfileReader.cxx b/Source/cmGccDepfileReader.cxx new file mode 100644 index 0000000..9d70ede --- /dev/null +++ b/Source/cmGccDepfileReader.cxx @@ -0,0 +1,18 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmGccDepfileReader.h" + +#include <type_traits> +#include <utility> + +#include "cmGccDepfileLexerHelper.h" + +cmGccDepfileContent cmReadGccDepfile(const char* filePath) +{ + cmGccDepfileContent result; + cmGccDepfileLexerHelper helper; + if (helper.readFile(filePath)) { + result = std::move(helper).extractContent(); + } + return result; +} diff --git a/Source/cmGccDepfileReader.h b/Source/cmGccDepfileReader.h new file mode 100644 index 0000000..9313010 --- /dev/null +++ b/Source/cmGccDepfileReader.h @@ -0,0 +1,10 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmGccDepfileReader_h +#define cmGccDepfileReader_h + +#include "cmGccDepfileReaderTypes.h" + +cmGccDepfileContent cmReadGccDepfile(const char* filePath); + +#endif diff --git a/Source/cmGccDepfileReaderTypes.h b/Source/cmGccDepfileReaderTypes.h new file mode 100644 index 0000000..8b15c73 --- /dev/null +++ b/Source/cmGccDepfileReaderTypes.h @@ -0,0 +1,17 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmGccDepfileReaderTypes_h +#define cmGccDepfileReaderTypes_h + +#include <string> +#include <vector> + +struct cmGccStyleDependency +{ + std::vector<std::string> rules; + std::vector<std::string> paths; +}; + +using cmGccDepfileContent = std::vector<cmGccStyleDependency>; + +#endif diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx index 2af04b6..f76e205 100644 --- a/Source/cmGeneratedFileStream.cxx +++ b/Source/cmGeneratedFileStream.cxx @@ -180,6 +180,7 @@ int cmGeneratedFileStreamBase::CompressFile(std::string const& oldname, } FILE* ifs = cmsys::SystemTools::Fopen(oldname, "r"); if (!ifs) { + gzclose(gf); return 0; } size_t res; diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index b7f7d1d..6e293d5 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -8,7 +8,6 @@ #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmGeneratorExpressionContext.h" #include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorExpressionEvaluator.h" @@ -22,6 +21,8 @@ cmGeneratorExpression::cmGeneratorExpression(cmListFileBacktrace backtrace) { } +cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression() = default; + cmGeneratorExpression::~cmGeneratorExpression() = default; std::unique_ptr<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse( @@ -31,12 +32,6 @@ std::unique_ptr<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse( new cmCompiledGeneratorExpression(this->Backtrace, std::move(input))); } -std::unique_ptr<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse( - const char* input) const -{ - return this->Parse(std::string(input ? input : "")); -} - std::string cmGeneratorExpression::Evaluate( std::string input, cmLocalGenerator* lg, const std::string& config, cmGeneratorTarget const* headTarget, @@ -51,17 +46,6 @@ std::string cmGeneratorExpression::Evaluate( return input; } -std::string cmGeneratorExpression::Evaluate( - const char* input, cmLocalGenerator* lg, const std::string& config, - cmGeneratorTarget const* headTarget, - cmGeneratorExpressionDAGChecker* dagChecker, - cmGeneratorTarget const* currentTarget, std::string const& language) -{ - return input ? Evaluate(std::string(input), lg, config, headTarget, - dagChecker, currentTarget, language) - : ""; -} - const std::string& cmCompiledGeneratorExpression::Evaluate( cmLocalGenerator* lg, const std::string& config, const cmGeneratorTarget* headTarget, @@ -86,7 +70,7 @@ const std::string& cmCompiledGeneratorExpression::EvaluateWithContext( this->Output.clear(); - for (const cmGeneratorExpressionEvaluator* it : this->Evaluators) { + for (const auto& it : this->Evaluators) { this->Output += it->Evaluate(&context, dagChecker); this->SeenTargetProperties.insert(context.SeenTargetProperties.cbegin(), @@ -102,6 +86,8 @@ const std::string& cmCompiledGeneratorExpression::EvaluateWithContext( if (!context.HadError) { this->HadContextSensitiveCondition = context.HadContextSensitiveCondition; this->HadHeadSensitiveCondition = context.HadHeadSensitiveCondition; + this->HadLinkLanguageSensitiveCondition = + context.HadLinkLanguageSensitiveCondition; this->SourceSensitiveTargets = context.SourceSensitiveTargets; } @@ -118,6 +104,7 @@ cmCompiledGeneratorExpression::cmCompiledGeneratorExpression( , Quiet(false) , HadContextSensitiveCondition(false) , HadHeadSensitiveCondition(false) + , HadLinkLanguageSensitiveCondition(false) { cmGeneratorExpressionLexer l; std::vector<cmGeneratorExpressionToken> tokens = l.Tokenize(this->Input); @@ -129,11 +116,6 @@ cmCompiledGeneratorExpression::cmCompiledGeneratorExpression( } } -cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression() -{ - cmDeleteAll(this->Evaluators); -} - std::string cmGeneratorExpression::StripEmptyListElements( const std::string& input) { @@ -385,6 +367,20 @@ bool cmGeneratorExpression::IsValidTargetName(const std::string& input) return targetNameValidator.find(input); } +void cmGeneratorExpression::ReplaceInstallPrefix( + std::string& input, const std::string& replacement) +{ + std::string::size_type pos = 0; + std::string::size_type lastPos = pos; + + while ((pos = input.find("$<INSTALL_PREFIX>", lastPos)) != + std::string::npos) { + std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1; + input.replace(pos, endPos - pos, replacement); + lastPos = endPos; + } +} + void cmCompiledGeneratorExpression::GetMaxLanguageStandard( const cmGeneratorTarget* tgt, std::map<std::string, std::string>& mapping) { diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index 4bd1c9f..75bba02 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -42,8 +42,6 @@ public: std::unique_ptr<cmCompiledGeneratorExpression> Parse( std::string input) const; - std::unique_ptr<cmCompiledGeneratorExpression> Parse( - const char* input) const; static std::string Evaluate( std::string input, cmLocalGenerator* lg, const std::string& config, @@ -51,12 +49,6 @@ public: cmGeneratorExpressionDAGChecker* dagChecker = nullptr, cmGeneratorTarget const* currentTarget = nullptr, std::string const& language = std::string()); - static std::string Evaluate( - const char* input, cmLocalGenerator* lg, const std::string& config, - cmGeneratorTarget const* headTarget = nullptr, - cmGeneratorExpressionDAGChecker* dagChecker = nullptr, - cmGeneratorTarget const* currentTarget = nullptr, - std::string const& language = std::string()); enum PreprocessContext { @@ -87,6 +79,9 @@ public: return input != nullptr && input[0] == '$' && input[1] == '<'; } + static void ReplaceInstallPrefix(std::string& input, + const std::string& replacement); + private: cmListFileBacktrace Backtrace; }; @@ -134,6 +129,10 @@ public: { return this->HadHeadSensitiveCondition; } + bool GetHadLinkLanguageSensitiveCondition() const + { + return this->HadLinkLanguageSensitiveCondition; + } std::set<cmGeneratorTarget const*> GetSourceSensitiveTargets() const { return this->SourceSensitiveTargets; @@ -160,7 +159,7 @@ private: friend class cmGeneratorExpression; cmListFileBacktrace Backtrace; - std::vector<cmGeneratorExpressionEvaluator*> Evaluators; + std::vector<std::unique_ptr<cmGeneratorExpressionEvaluator>> Evaluators; const std::string Input; bool NeedsEvaluation; bool EvaluateForBuildsystem; @@ -175,6 +174,7 @@ private: mutable std::string Output; mutable bool HadContextSensitiveCondition; mutable bool HadHeadSensitiveCondition; + mutable bool HadLinkLanguageSensitiveCondition; mutable std::set<cmGeneratorTarget const*> SourceSensitiveTargets; }; diff --git a/Source/cmGeneratorExpressionContext.cxx b/Source/cmGeneratorExpressionContext.cxx index 6d97331..42cbe2a 100644 --- a/Source/cmGeneratorExpressionContext.cxx +++ b/Source/cmGeneratorExpressionContext.cxx @@ -19,6 +19,7 @@ cmGeneratorExpressionContext::cmGeneratorExpressionContext( , HadError(false) , HadContextSensitiveCondition(false) , HadHeadSensitiveCondition(false) + , HadLinkLanguageSensitiveCondition(false) , EvaluateForBuildsystem(evaluateForBuildsystem) { } diff --git a/Source/cmGeneratorExpressionContext.h b/Source/cmGeneratorExpressionContext.h index 4709fa0..bceff12 100644 --- a/Source/cmGeneratorExpressionContext.h +++ b/Source/cmGeneratorExpressionContext.h @@ -40,6 +40,7 @@ struct cmGeneratorExpressionContext bool HadError; bool HadContextSensitiveCondition; bool HadHeadSensitiveCondition; + bool HadLinkLanguageSensitiveCondition; bool EvaluateForBuildsystem; }; diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index 643ba34..2c73289 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -6,6 +6,10 @@ #include <sstream> #include <utility> +#include <cm/string_view> + +#include "cm_static_string_view.hxx" + #include "cmGeneratorExpressionContext.h" #include "cmGeneratorExpressionEvaluator.h" #include "cmGeneratorTarget.h" @@ -170,6 +174,21 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() return top->Property == "INTERFACE_POSITION_INDEPENDENT_CODE"; } +bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() +{ + const cmGeneratorExpressionDAGChecker* top = this; + const cmGeneratorExpressionDAGChecker* parent = this->Parent; + while (parent) { + top = parent; + parent = parent->Parent; + } + + cm::string_view property(top->Property); + + return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s || + property == "LINK_DEPENDS"_s; +} + bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries( cmGeneratorTarget const* tgt) { @@ -180,18 +199,17 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries( parent = parent->Parent; } - const char* prop = top->Property.c_str(); + cm::string_view prop(top->Property); if (tgt) { - return top->Target == tgt && strcmp(prop, "LINK_LIBRARIES") == 0; + return top->Target == tgt && prop == "LINK_LIBRARIES"_s; } - return (strcmp(prop, "LINK_LIBRARIES") == 0 || - strcmp(prop, "LINK_INTERFACE_LIBRARIES") == 0 || - strcmp(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES") == 0 || - cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") || - cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_")) || - strcmp(prop, "INTERFACE_LINK_LIBRARIES") == 0; + return prop == "LINK_LIBRARIES"_s || prop == "LINK_INTERFACE_LIBRARIES"_s || + prop == "IMPORTED_LINK_INTERFACE_LIBRARIES"_s || + cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") || + cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_") || + prop == "INTERFACE_LINK_LIBRARIES"_s; } cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index f2c49bb..2a06596 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -68,6 +68,7 @@ struct cmGeneratorExpressionDAGChecker bool EvaluatingGenexExpression(); bool EvaluatingPICExpression(); + bool EvaluatingLinkExpression(); bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr); #define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const; diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index e0ae170..4129a0c 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -2,10 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGeneratorExpressionEvaluator.h" -#include <algorithm> #include <sstream> -#include "cmAlgorithms.h" #include "cmGeneratorExpressionContext.h" #include "cmGeneratorExpressionNode.h" @@ -16,6 +14,8 @@ GeneratorExpressionContent::GeneratorExpressionContent( { } +GeneratorExpressionContent::~GeneratorExpressionContent() = default; + std::string GeneratorExpressionContent::GetOriginalExpression() const { return std::string(this->StartContent, this->ContentLength); @@ -25,14 +25,13 @@ std::string GeneratorExpressionContent::ProcessArbitraryContent( const cmGeneratorExpressionNode* node, const std::string& identifier, cmGeneratorExpressionContext* context, cmGeneratorExpressionDAGChecker* dagChecker, - std::vector<std::vector<cmGeneratorExpressionEvaluator*>>::const_iterator - pit) const + std::vector<cmGeneratorExpressionEvaluatorVector>::const_iterator pit) const { std::string result; const auto pend = this->ParamChildren.end(); for (; pit != pend; ++pit) { - for (cmGeneratorExpressionEvaluator* pExprEval : *pit) { + for (auto& pExprEval : *pit) { if (node->RequiresLiteralInput()) { if (pExprEval->GetType() != cmGeneratorExpressionEvaluator::Text) { reportError(context, this->GetOriginalExpression(), @@ -64,8 +63,7 @@ std::string GeneratorExpressionContent::Evaluate( { std::string identifier; { - for (cmGeneratorExpressionEvaluator* pExprEval : - this->IdentifierChildren) { + for (auto& pExprEval : this->IdentifierChildren) { identifier += pExprEval->Evaluate(context, dagChecker); if (context->HadError) { return std::string(); @@ -126,7 +124,7 @@ std::string GeneratorExpressionContent::EvaluateParameters( return std::string(); } std::string parameter; - for (cmGeneratorExpressionEvaluator* pExprEval : *pit) { + for (auto& pExprEval : *pit) { parameter += pExprEval->Evaluate(context, dagChecker); if (context->HadError) { return std::string(); @@ -174,10 +172,3 @@ std::string GeneratorExpressionContent::EvaluateParameters( } return std::string(); } - -GeneratorExpressionContent::~GeneratorExpressionContent() -{ - cmDeleteAll(this->IdentifierChildren); - std::for_each(this->ParamChildren.begin(), this->ParamChildren.end(), - cmDeleteAll<std::vector<cmGeneratorExpressionEvaluator*>>); -} diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index b10bb5b..10496fd 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <cstddef> +#include <memory> #include <string> #include <utility> #include <vector> @@ -36,6 +37,9 @@ struct cmGeneratorExpressionEvaluator cmGeneratorExpressionDAGChecker*) const = 0; }; +using cmGeneratorExpressionEvaluatorVector = + std::vector<std::unique_ptr<cmGeneratorExpressionEvaluator>>; + struct TextContent : public cmGeneratorExpressionEvaluator { TextContent(const char* start, size_t length) @@ -68,13 +72,13 @@ struct GeneratorExpressionContent : public cmGeneratorExpressionEvaluator { GeneratorExpressionContent(const char* startContent, size_t length); - void SetIdentifier(std::vector<cmGeneratorExpressionEvaluator*> identifier) + void SetIdentifier(cmGeneratorExpressionEvaluatorVector&& identifier) { this->IdentifierChildren = std::move(identifier); } void SetParameters( - std::vector<std::vector<cmGeneratorExpressionEvaluator*>> parameters) + std::vector<cmGeneratorExpressionEvaluatorVector>&& parameters) { this->ParamChildren = std::move(parameters); } @@ -102,12 +106,12 @@ private: const cmGeneratorExpressionNode* node, const std::string& identifier, cmGeneratorExpressionContext* context, cmGeneratorExpressionDAGChecker* dagChecker, - std::vector<std::vector<cmGeneratorExpressionEvaluator*>>::const_iterator - pit) const; + std::vector<cmGeneratorExpressionEvaluatorVector>::const_iterator pit) + const; private: - std::vector<cmGeneratorExpressionEvaluator*> IdentifierChildren; - std::vector<std::vector<cmGeneratorExpressionEvaluator*>> ParamChildren; + cmGeneratorExpressionEvaluatorVector IdentifierChildren; + std::vector<cmGeneratorExpressionEvaluatorVector> ParamChildren; const char* StartContent; size_t ContentLength; }; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 66f1c71..8831d0f 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -14,6 +14,7 @@ #include <utility> #include <cm/iterator> +#include <cm/string_view> #include "cmsys/RegularExpression.hxx" #include "cmsys/String.h" @@ -37,7 +38,6 @@ #include "cmState.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" -#include "cmString.hxx" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" @@ -62,6 +62,9 @@ std::string cmGeneratorExpressionNode::EvaluateDependentExpression( if (cge->GetHadHeadSensitiveCondition()) { context->HadHeadSensitiveCondition = true; } + if (cge->GetHadLinkLanguageSensitiveCondition()) { + context->HadLinkLanguageSensitiveCondition = true; + } return result; } @@ -1039,6 +1042,150 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode } } languageAndIdNode; +static const struct LinkLanguageNode : public cmGeneratorExpressionNode +{ + LinkLanguageNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return ZeroOrMoreParameters; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* dagChecker) const override + { + if (!context->HeadTarget || !dagChecker || + !(dagChecker->EvaluatingLinkExpression() || + dagChecker->EvaluatingLinkLibraries())) { + reportError(context, content->GetOriginalExpression(), + "$<LINK_LANGUAGE:...> may only be used with binary targets " + "to specify link libraries, link directories, link options " + "and link depends."); + return std::string(); + } + if (dagChecker->EvaluatingLinkLibraries() && parameters.empty()) { + reportError( + context, content->GetOriginalExpression(), + "$<LINK_LANGUAGE> is not supported in link libraries expression."); + return std::string(); + } + + cmGlobalGenerator* gg = context->LG->GetGlobalGenerator(); + std::string genName = gg->GetName(); + if (genName.find("Makefiles") == std::string::npos && + genName.find("Ninja") == std::string::npos && + genName.find("Visual Studio") == std::string::npos && + genName.find("Xcode") == std::string::npos && + genName.find("Watcom WMake") == std::string::npos) { + reportError(context, content->GetOriginalExpression(), + "$<LINK_LANGUAGE:...> not supported for this generator."); + return std::string(); + } + + if (dagChecker->EvaluatingLinkLibraries()) { + context->HadHeadSensitiveCondition = true; + context->HadLinkLanguageSensitiveCondition = true; + } + + if (parameters.empty()) { + return context->Language; + } + + for (auto& param : parameters) { + if (context->Language == param) { + return "1"; + } + } + return "0"; + } +} linkLanguageNode; + +namespace { +struct LinkerId +{ + static std::string Evaluate(const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + const std::string& lang) + { + std::string const& linkerId = + context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang + + "_COMPILER_ID"); + if (parameters.empty()) { + return linkerId; + } + if (linkerId.empty()) { + return parameters.front().empty() ? "1" : "0"; + } + static cmsys::RegularExpression linkerIdValidator("^[A-Za-z0-9_]*$"); + + for (auto& param : parameters) { + if (!linkerIdValidator.find(param)) { + reportError(context, content->GetOriginalExpression(), + "Expression syntax not recognized."); + return std::string(); + } + + if (param == linkerId) { + return "1"; + } + } + return "0"; + } +}; +} + +static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode +{ + LinkLanguageAndIdNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return TwoOrMoreParameters; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* dagChecker) const override + { + if (!context->HeadTarget || !dagChecker || + !(dagChecker->EvaluatingLinkExpression() || + dagChecker->EvaluatingLinkLibraries())) { + reportError( + context, content->GetOriginalExpression(), + "$<LINK_LANG_AND_ID:lang,id> may only be used with binary targets " + "to specify link libraries, link directories, link options, and link " + "depends."); + return std::string(); + } + + cmGlobalGenerator* gg = context->LG->GetGlobalGenerator(); + std::string genName = gg->GetName(); + if (genName.find("Makefiles") == std::string::npos && + genName.find("Ninja") == std::string::npos && + genName.find("Visual Studio") == std::string::npos && + genName.find("Xcode") == std::string::npos && + genName.find("Watcom WMake") == std::string::npos) { + reportError( + context, content->GetOriginalExpression(), + "$<LINK_LANG_AND_ID:lang,id> not supported for this generator."); + return std::string(); + } + + if (dagChecker->EvaluatingLinkLibraries()) { + context->HadHeadSensitiveCondition = true; + context->HadLinkLanguageSensitiveCondition = true; + } + + const std::string& lang = context->Language; + if (lang == parameters.front()) { + std::vector<std::string> idParameter((parameters.cbegin() + 1), + parameters.cend()); + return LinkerId::Evaluate(idParameter, context, content, lang); + } + return "0"; + } +} linkLanguageAndIdNode; + std::string getLinkedTargetsContent( cmGeneratorTarget const* target, std::string const& prop, cmGeneratorExpressionContext* context, @@ -2314,6 +2461,8 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "LINK_ONLY", &linkOnlyNode }, { "COMPILE_LANG_AND_ID", &languageAndIdNode }, { "COMPILE_LANGUAGE", &languageNode }, + { "LINK_LANG_AND_ID", &linkLanguageAndIdNode }, + { "LINK_LANGUAGE", &linkLanguageNode }, { "SHELL_PATH", &shellPathNode } }; diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx index d6cc6ab..c2c9ef7 100644 --- a/Source/cmGeneratorExpressionParser.cxx +++ b/Source/cmGeneratorExpressionParser.cxx @@ -6,7 +6,10 @@ #include <cstddef> #include <utility> -#include "cmAlgorithms.h" +#include <cm/memory> +#include <cmext/algorithm> +#include <cmext/memory> + #include "cmGeneratorExpressionEvaluator.h" cmGeneratorExpressionParser::cmGeneratorExpressionParser( @@ -17,7 +20,7 @@ cmGeneratorExpressionParser::cmGeneratorExpressionParser( } void cmGeneratorExpressionParser::Parse( - std::vector<cmGeneratorExpressionEvaluator*>& result) + cmGeneratorExpressionEvaluatorVector& result) { it = this->Tokens.begin(); @@ -27,40 +30,38 @@ void cmGeneratorExpressionParser::Parse( } static void extendText( - std::vector<cmGeneratorExpressionEvaluator*>& result, + cmGeneratorExpressionEvaluatorVector& result, std::vector<cmGeneratorExpressionToken>::const_iterator it) { if (!result.empty() && (*(result.end() - 1))->GetType() == cmGeneratorExpressionEvaluator::Text) { - TextContent* textContent = static_cast<TextContent*>(*(result.end() - 1)); - textContent->Extend(it->Length); + cm::static_reference_cast<TextContent>(*(result.end() - 1)) + .Extend(it->Length); } else { - TextContent* textContent = new TextContent(it->Content, it->Length); - result.push_back(textContent); + auto textContent = cm::make_unique<TextContent>(it->Content, it->Length); + result.push_back(std::move(textContent)); } } static void extendResult( - std::vector<cmGeneratorExpressionEvaluator*>& result, - const std::vector<cmGeneratorExpressionEvaluator*>& contents) + cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector& result, + cmGeneratorExpressionParser::cmGeneratorExpressionEvaluatorVector&& contents) { if (!result.empty() && (*(result.end() - 1))->GetType() == cmGeneratorExpressionEvaluator::Text && contents.front()->GetType() == cmGeneratorExpressionEvaluator::Text) { - TextContent* textContent = static_cast<TextContent*>(*(result.end() - 1)); - textContent->Extend( - static_cast<TextContent*>(contents.front())->GetLength()); - delete contents.front(); - cmAppend(result, contents.begin() + 1, contents.end()); - } else { - cmAppend(result, contents); + cm::static_reference_cast<TextContent>(*(result.end() - 1)) + .Extend( + cm::static_reference_cast<TextContent>(contents.front()).GetLength()); + contents.erase(contents.begin()); } + cm::append(result, std::move(contents)); } void cmGeneratorExpressionParser::ParseGeneratorExpression( - std::vector<cmGeneratorExpressionEvaluator*>& result) + cmGeneratorExpressionEvaluatorVector& result) { assert(this->it != this->Tokens.end()); unsigned int nestedLevel = this->NestingLevel; @@ -68,7 +69,7 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( auto startToken = this->it - 1; - std::vector<cmGeneratorExpressionEvaluator*> identifier; + cmGeneratorExpressionEvaluatorVector identifier; while (this->it->TokenType != cmGeneratorExpressionToken::EndExpression && this->it->TokenType != cmGeneratorExpressionToken::ColonSeparator) { if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) { @@ -87,18 +88,18 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( if (this->it != this->Tokens.end() && this->it->TokenType == cmGeneratorExpressionToken::EndExpression) { - GeneratorExpressionContent* content = new GeneratorExpressionContent( + auto content = cm::make_unique<GeneratorExpressionContent>( startToken->Content, this->it->Content - startToken->Content + this->it->Length); assert(this->it != this->Tokens.end()); ++this->it; --this->NestingLevel; content->SetIdentifier(std::move(identifier)); - result.push_back(content); + result.push_back(std::move(content)); return; } - std::vector<std::vector<cmGeneratorExpressionEvaluator*>> parameters; + std::vector<cmGeneratorExpressionEvaluatorVector> parameters; std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator> commaTokens; std::vector<cmGeneratorExpressionToken>::const_iterator colonToken; @@ -169,7 +170,7 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( // treat the '$<' as having been plain text, along with the // corresponding : and , tokens that might have been found. extendText(result, startToken); - extendResult(result, identifier); + extendResult(result, std::move(identifier)); if (!parameters.empty()) { extendText(result, colonToken); @@ -179,7 +180,7 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( assert(parameters.size() > commaTokens.size()); for (; pit != pend; ++pit, ++commaIt) { if (!pit->empty() && !emptyParamTermination) { - extendResult(result, *pit); + extendResult(result, std::move(*pit)); } if (commaIt != commaTokens.end()) { extendText(result, *commaIt); @@ -193,15 +194,15 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression( size_t contentLength = ((this->it - 1)->Content - startToken->Content) + (this->it - 1)->Length; - GeneratorExpressionContent* content = - new GeneratorExpressionContent(startToken->Content, contentLength); + auto content = cm::make_unique<GeneratorExpressionContent>( + startToken->Content, contentLength); content->SetIdentifier(std::move(identifier)); content->SetParameters(std::move(parameters)); - result.push_back(content); + result.push_back(std::move(content)); } void cmGeneratorExpressionParser::ParseContent( - std::vector<cmGeneratorExpressionEvaluator*>& result) + cmGeneratorExpressionEvaluatorVector& result) { assert(this->it != this->Tokens.end()); switch (this->it->TokenType) { @@ -213,17 +214,16 @@ void cmGeneratorExpressionParser::ParseContent( // A comma in 'plain text' could have split text that should // otherwise be continuous. Extend the last text content instead of // creating a new one. - TextContent* textContent = - static_cast<TextContent*>(*(result.end() - 1)); - textContent->Extend(this->it->Length); + cm::static_reference_cast<TextContent>(*(result.end() - 1)) + .Extend(this->it->Length); assert(this->it != this->Tokens.end()); ++this->it; return; } } - cmGeneratorExpressionEvaluator* n = - new TextContent(this->it->Content, this->it->Length); - result.push_back(n); + auto n = + cm::make_unique<TextContent>(this->it->Content, this->it->Length); + result.push_back(std::move(n)); assert(this->it != this->Tokens.end()); ++this->it; return; diff --git a/Source/cmGeneratorExpressionParser.h b/Source/cmGeneratorExpressionParser.h index e663496..1ba1654 100644 --- a/Source/cmGeneratorExpressionParser.h +++ b/Source/cmGeneratorExpressionParser.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <memory> #include <vector> #include "cmGeneratorExpressionLexer.h" @@ -15,11 +16,14 @@ struct cmGeneratorExpressionParser { cmGeneratorExpressionParser(std::vector<cmGeneratorExpressionToken> tokens); - void Parse(std::vector<cmGeneratorExpressionEvaluator*>& result); + using cmGeneratorExpressionEvaluatorVector = + std::vector<std::unique_ptr<cmGeneratorExpressionEvaluator>>; + + void Parse(cmGeneratorExpressionEvaluatorVector& result); private: - void ParseContent(std::vector<cmGeneratorExpressionEvaluator*>&); - void ParseGeneratorExpression(std::vector<cmGeneratorExpressionEvaluator*>&); + void ParseContent(cmGeneratorExpressionEvaluatorVector&); + void ParseGeneratorExpression(cmGeneratorExpressionEvaluatorVector&); private: std::vector<cmGeneratorExpressionToken>::const_iterator it; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 171c3ed..ad142d7 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -10,14 +10,14 @@ #include <cstdlib> #include <cstring> #include <iterator> -#include <memory> +#include <queue> #include <sstream> #include <unordered_set> #include <utility> +#include <cm/memory> #include <cm/string_view> - -#include <queue> +#include <cmext/algorithm> #include "cmsys/RegularExpression.hxx" @@ -26,6 +26,7 @@ #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" #include "cmCustomCommandLines.h" +#include "cmFileTimes.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionContext.h" @@ -55,11 +56,11 @@ const char* cmTargetPropertyComputer::GetSources<cmGeneratorTarget>( cmGeneratorTarget const* tgt, cmMessenger* /* messenger */, cmListFileBacktrace const& /* context */) { - return tgt->GetSourcesProperty(); + return tgt->GetSourcesProperty().c_str(); } template <> -const char* +const std::string& cmTargetPropertyComputer::ComputeLocationForBuild<cmGeneratorTarget>( cmGeneratorTarget const* tgt) { @@ -67,7 +68,8 @@ cmTargetPropertyComputer::ComputeLocationForBuild<cmGeneratorTarget>( } template <> -const char* cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>( +const std::string& +cmTargetPropertyComputer::ComputeLocation<cmGeneratorTarget>( cmGeneratorTarget const* tgt, const std::string& config) { return tgt->GetLocation(config); @@ -162,7 +164,8 @@ private: cmListFileBacktrace Backtrace; }; -cmGeneratorTarget::TargetPropertyEntry* CreateTargetPropertyEntry( +std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry> +CreateTargetPropertyEntry( const std::string& propertyValue, cmListFileBacktrace backtrace = cmListFileBacktrace(), bool evaluateForBuildsystem = false) @@ -172,15 +175,18 @@ cmGeneratorTarget::TargetPropertyEntry* CreateTargetPropertyEntry( std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(propertyValue); cge->SetEvaluateForBuildsystem(evaluateForBuildsystem); - return new TargetPropertyEntryGenex(std::move(cge)); + return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>( + cm::make_unique<TargetPropertyEntryGenex>(std::move(cge))); } - return new TargetPropertyEntryString(propertyValue, std::move(backtrace)); + return std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>( + cm::make_unique<TargetPropertyEntryString>(propertyValue, + std::move(backtrace))); } void CreatePropertyGeneratorExpressions( cmStringRange entries, cmBacktraceRange backtraces, - std::vector<cmGeneratorTarget::TargetPropertyEntry*>& items, + std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items, bool evaluateForBuildsystem = false) { auto btIt = backtraces.begin(); @@ -219,13 +225,13 @@ struct EvaluatedTargetPropertyEntry EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry( cmGeneratorTarget const* thisTarget, std::string const& config, std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, - cmGeneratorTarget::TargetPropertyEntry* entry) + cmGeneratorTarget::TargetPropertyEntry& entry) { - EvaluatedTargetPropertyEntry ee(entry->LinkImplItem, entry->GetBacktrace()); - cmExpandList(entry->Evaluate(thisTarget->GetLocalGenerator(), config, - thisTarget, dagChecker, lang), + EvaluatedTargetPropertyEntry ee(entry.LinkImplItem, entry.GetBacktrace()); + cmExpandList(entry.Evaluate(thisTarget->GetLocalGenerator(), config, + thisTarget, dagChecker, lang), ee.Values); - if (entry->GetHadContextSensitiveCondition()) { + if (entry.GetHadContextSensitiveCondition()) { ee.ContextDependent = true; } return ee; @@ -234,13 +240,14 @@ EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry( std::vector<EvaluatedTargetPropertyEntry> EvaluateTargetPropertyEntries( cmGeneratorTarget const* thisTarget, std::string const& config, std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, - std::vector<cmGeneratorTarget::TargetPropertyEntry*> const& in) + std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>> const& + in) { std::vector<EvaluatedTargetPropertyEntry> out; out.reserve(in.size()); - for (cmGeneratorTarget::TargetPropertyEntry* entry : in) { + for (auto& entry : in) { out.emplace_back(EvaluateTargetPropertyEntry(thisTarget, config, lang, - dagChecker, entry)); + dagChecker, *entry)); } return out; } @@ -302,31 +309,27 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) this->SourceEntries, true); this->PolicyMap = t->GetPolicyMap(); -} -cmGeneratorTarget::~cmGeneratorTarget() -{ - cmDeleteAll(this->IncludeDirectoriesEntries); - cmDeleteAll(this->CompileOptionsEntries); - cmDeleteAll(this->CompileFeaturesEntries); - cmDeleteAll(this->CompileDefinitionsEntries); - cmDeleteAll(this->LinkOptionsEntries); - cmDeleteAll(this->LinkDirectoriesEntries); - cmDeleteAll(this->PrecompileHeadersEntries); - cmDeleteAll(this->SourceEntries); - cmDeleteAll(this->LinkInformation); + // Get hard-coded linker language + if (this->Target->GetProperty("HAS_CXX")) { + this->LinkerLanguage = "CXX"; + } else { + this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE"); + } } -const char* cmGeneratorTarget::GetSourcesProperty() const +cmGeneratorTarget::~cmGeneratorTarget() = default; + +const std::string& cmGeneratorTarget::GetSourcesProperty() const { std::vector<std::string> values; - for (TargetPropertyEntry* se : this->SourceEntries) { + for (auto& se : this->SourceEntries) { values.push_back(se->GetInput()); } static std::string value; value.clear(); value = cmJoin(values, ";"); - return value.c_str(); + return value; } cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const @@ -536,15 +539,43 @@ std::string cmGeneratorTarget::GetFileSuffix( std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const { const char* postfix = nullptr; + std::string frameworkPostfix; if (!config.empty()) { std::string configProp = cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX"); postfix = this->GetProperty(configProp); - // Mac application bundles and frameworks have no postfix. + + // Mac application bundles and frameworks have no regular postfix like + // libraries do. if (!this->IsImported() && postfix && (this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) { postfix = nullptr; } + + // Frameworks created by multi config generators can have a special + // framework postfix. + frameworkPostfix = GetFrameworkMultiConfigPostfix(config); + if (!frameworkPostfix.empty()) { + postfix = frameworkPostfix.c_str(); + } + } + return postfix ? postfix : std::string(); +} + +std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix( + const std::string& config) const +{ + const char* postfix = nullptr; + if (!config.empty()) { + std::string configProp = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_", + cmSystemTools::UpperCase(config)); + postfix = this->GetProperty(configProp); + + if (!this->IsImported() && postfix && + (this->IsFrameworkOnApple() && + !GetGlobalGenerator()->IsMultiConfig())) { + postfix = nullptr; + } } return postfix ? postfix : std::string(); } @@ -655,6 +686,7 @@ void cmGeneratorTarget::ClearSourcesCache() this->KindedSourcesMap.clear(); this->LinkImplementationLanguageIsContextDependent = true; this->Objects.clear(); + this->VisitedConfigsForObjects.clear(); } void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before) @@ -744,7 +776,7 @@ void cmGeneratorTarget::GetObjectSources( { IMPLEMENT_VISIT(SourceKindObjectSource); - if (!this->Objects.empty()) { + if (this->VisitedConfigsForObjects.count(config)) { return; } @@ -753,16 +785,17 @@ void cmGeneratorTarget::GetObjectSources( } this->LocalGenerator->ComputeObjectFilenames(this->Objects, this); + this->VisitedConfigsForObjects.insert(config); } void cmGeneratorTarget::ComputeObjectMapping() { - if (!this->Objects.empty()) { + auto const& configs = this->Makefile->GetGeneratorConfigs(); + std::set<std::string> configSet(configs.begin(), configs.end()); + if (configSet == this->VisitedConfigsForObjects) { return; } - std::vector<std::string> const& configs = - this->Makefile->GetGeneratorConfigs(); for (std::string const& c : configs) { std::vector<cmSourceFile const*> sourceFiles; this->GetObjectSources(sourceFiles, c); @@ -982,13 +1015,15 @@ std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const { if (!this->UtilityItemsDone) { this->UtilityItemsDone = true; - std::set<BT<std::string>> const& utilities = this->GetUtilities(); - for (BT<std::string> const& i : utilities) { + std::set<BT<std::pair<std::string, bool>>> const& utilities = + this->GetUtilities(); + for (BT<std::pair<std::string, bool>> const& i : utilities) { if (cmGeneratorTarget* gt = - this->LocalGenerator->FindGeneratorTargetToUse(i.Value)) { - this->UtilityItems.insert(cmLinkItem(gt, i.Backtrace)); + this->LocalGenerator->FindGeneratorTargetToUse(i.Value.first)) { + this->UtilityItems.insert(cmLinkItem(gt, i.Value.second, i.Backtrace)); } else { - this->UtilityItems.insert(cmLinkItem(i.Value, i.Backtrace)); + this->UtilityItems.insert( + cmLinkItem(i.Value.first, i.Value.second, i.Backtrace)); } } } @@ -1001,7 +1036,8 @@ void cmGeneratorTarget::GetXamlSources(std::vector<cmSourceFile const*>& data, IMPLEMENT_VISIT(SourceKindXaml); } -const char* cmGeneratorTarget::GetLocation(const std::string& config) const +const std::string& cmGeneratorTarget::GetLocation( + const std::string& config) const { static std::string location; if (this->IsImported()) { @@ -1010,7 +1046,7 @@ const char* cmGeneratorTarget::GetLocation(const std::string& config) const } else { location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact); } - return location.c_str(); + return location; } std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands() @@ -1041,13 +1077,13 @@ bool cmGeneratorTarget::IsImportedGloballyVisible() const return this->Target->IsImportedGloballyVisible(); } -const char* cmGeneratorTarget::GetLocationForBuild() const +const std::string& cmGeneratorTarget::GetLocationForBuild() const { static std::string location; if (this->IsImported()) { location = this->Target->ImportedGetFullPath( "", cmStateEnums::RuntimeBinaryArtifact); - return location.c_str(); + return location; } // Now handle the deprecated build-time configuration location. @@ -1067,7 +1103,7 @@ const char* cmGeneratorTarget::GetLocationForBuild() const } location += "/"; location += this->GetFullName("", cmStateEnums::RuntimeBinaryArtifact); - return location.c_str(); + return location; } bool cmGeneratorTarget::IsSystemIncludeDirectory( @@ -1122,7 +1158,8 @@ bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const } bool cmGeneratorTarget::MaybeHaveInterfaceProperty( - std::string const& prop, cmGeneratorExpressionContext* context) const + std::string const& prop, cmGeneratorExpressionContext* context, + bool usage_requirements_only) const { std::string const key = prop + '@' + context->Config; auto i = this->MaybeInterfacePropertyExists.find(key); @@ -1141,7 +1178,7 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( context->HeadTarget ? context->HeadTarget : this; if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries(context->Config, headTarget, - true)) { + usage_requirements_only)) { if (iface->HadHeadSensitiveCondition) { // With a different head target we may get to a library with // this interface property. @@ -1151,7 +1188,8 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( // head target, so we can follow them. for (cmLinkItem const& lib : iface->Libraries) { if (lib.Target && - lib.Target->MaybeHaveInterfaceProperty(prop, context)) { + lib.Target->MaybeHaveInterfaceProperty( + prop, context, usage_requirements_only)) { maybeInterfaceProp = true; break; } @@ -1165,12 +1203,14 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( std::string cmGeneratorTarget::EvaluateInterfaceProperty( std::string const& prop, cmGeneratorExpressionContext* context, - cmGeneratorExpressionDAGChecker* dagCheckerParent) const + cmGeneratorExpressionDAGChecker* dagCheckerParent, + bool usage_requirements_only) const { std::string result; // If the property does not appear transitively at all, we are done. - if (!this->MaybeHaveInterfaceProperty(prop, context)) { + if (!this->MaybeHaveInterfaceProperty(prop, context, + usage_requirements_only)) { return result; } @@ -1202,8 +1242,8 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( p, context->LG, context, headTarget, &dagChecker, this); } - if (cmLinkInterfaceLibraries const* iface = - this->GetLinkInterfaceLibraries(context->Config, headTarget, true)) { + if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries( + context->Config, headTarget, usage_requirements_only)) { for (cmLinkItem const& lib : iface->Libraries) { // Broken code can have a target in its own link interface. // Don't follow such link interface entries so as not to create a @@ -1217,8 +1257,8 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( context->EvaluateForBuildsystem, context->Backtrace, context->Language); std::string libResult = cmGeneratorExpression::StripEmptyListElements( - lib.Target->EvaluateInterfaceProperty(prop, &libContext, - &dagChecker)); + lib.Target->EvaluateInterfaceProperty(prop, &libContext, &dagChecker, + usage_requirements_only)); if (!libResult.empty()) { if (result.empty()) { result = std::move(libResult); @@ -1246,7 +1286,8 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget, std::string const& config, std::string const& prop, std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, - std::vector<EvaluatedTargetPropertyEntry>& entries) + std::vector<EvaluatedTargetPropertyEntry>& entries, + bool usage_requirements_only = true) { if (cmLinkImplementationLibraries const* impl = headTarget->GetLinkImplementationLibraries(config)) { @@ -1259,9 +1300,9 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget, cmGeneratorExpressionContext context( headTarget->GetLocalGenerator(), config, false, headTarget, headTarget, true, lib.Backtrace, lang); - cmExpandList( - lib.Target->EvaluateInterfaceProperty(prop, &context, dagChecker), - ee.Values); + cmExpandList(lib.Target->EvaluateInterfaceProperty( + prop, &context, dagChecker, usage_requirements_only), + ee.Values); ee.ContextDependent = context.HadContextSensitiveCondition; entries.emplace_back(std::move(ee)); } @@ -1672,6 +1713,19 @@ void cmGeneratorTarget::ComputeAllConfigSources() const } } +std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const +{ + std::set<std::string> languages; + std::vector<AllConfigSource> const& sources = this->GetAllConfigSources(); + for (AllConfigSource const& si : sources) { + std::string const& lang = si.Source->GetOrDetermineLanguage(); + if (!lang.empty()) { + languages.emplace(lang); + } + } + return languages; +} + std::string cmGeneratorTarget::GetCompilePDBName( const std::string& config) const { @@ -2114,7 +2168,9 @@ std::string cmGeneratorTarget::GetInstallNameDirForBuildTree( // If building directly for installation then the build tree install_name // is the same as the install tree. if (this->MacOSXUseInstallNameDir()) { - return this->GetInstallNameDirForInstallTree(); + std::string installPrefix = + this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); + return this->GetInstallNameDirForInstallTree(config, installPrefix); } // Use the build tree directory for the target. @@ -2132,7 +2188,8 @@ std::string cmGeneratorTarget::GetInstallNameDirForBuildTree( return ""; } -std::string cmGeneratorTarget::GetInstallNameDirForInstallTree() const +std::string cmGeneratorTarget::GetInstallNameDirForInstallTree( + const std::string& config, const std::string& installPrefix) const { if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { std::string dir; @@ -2140,7 +2197,13 @@ std::string cmGeneratorTarget::GetInstallNameDirForInstallTree() const if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) { if (install_name_dir && *install_name_dir) { - dir = cmStrCat(install_name_dir, '/'); + dir = install_name_dir; + cmGeneratorExpression::ReplaceInstallPrefix(dir, installPrefix); + dir = + cmGeneratorExpression::Evaluate(dir, this->LocalGenerator, config); + if (!dir.empty()) { + dir = cmStrCat(dir, '/'); + } } } if (!install_name_dir) { @@ -2158,7 +2221,8 @@ cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const return this->Target->GetBacktrace(); } -const std::set<BT<std::string>>& cmGeneratorTarget::GetUtilities() const +const std::set<BT<std::pair<std::string, bool>>>& +cmGeneratorTarget::GetUtilities() const { return this->Target->GetUtilities(); } @@ -2195,11 +2259,12 @@ public: cmTargetCollectLinkLanguages(cmGeneratorTarget const* target, std::string config, std::unordered_set<std::string>& languages, - cmGeneratorTarget const* head) + cmGeneratorTarget const* head, bool secondPass) : Config(std::move(config)) , Languages(languages) , HeadTarget(head) , Target(target) + , SecondPass(secondPass) { this->Visited.insert(target); } @@ -2241,11 +2306,14 @@ public: if (!this->Visited.insert(item.Target).second) { return; } - cmLinkInterface const* iface = - item.Target->GetLinkInterface(this->Config, this->HeadTarget); + cmLinkInterface const* iface = item.Target->GetLinkInterface( + this->Config, this->HeadTarget, this->SecondPass); if (!iface) { return; } + if (iface->HadLinkLanguageSensitiveCondition) { + this->HadLinkLanguageSensitiveCondition = true; + } for (std::string const& language : iface->Languages) { this->Languages.insert(language); @@ -2256,12 +2324,19 @@ public: } } + bool GetHadLinkLanguageSensitiveCondition() + { + return HadLinkLanguageSensitiveCondition; + } + private: std::string Config; std::unordered_set<std::string>& Languages; cmGeneratorTarget const* HeadTarget; const cmGeneratorTarget* Target; std::set<cmGeneratorTarget const*> Visited; + bool SecondPass; + bool HadLinkLanguageSensitiveCondition = false; }; cmGeneratorTarget::LinkClosure const* cmGeneratorTarget::GetLinkClosure( @@ -2292,7 +2367,7 @@ public: { this->GG = this->Target->GetLocalGenerator()->GetGlobalGenerator(); } - void Consider(const char* lang) + void Consider(const std::string& lang) { int preference = this->GG->GetLinkerPreference(lang); if (preference > this->Preference) { @@ -2325,40 +2400,36 @@ public: } }; -void cmGeneratorTarget::ComputeLinkClosure(const std::string& config, - LinkClosure& lc) const +bool cmGeneratorTarget::ComputeLinkClosure(const std::string& config, + LinkClosure& lc, + bool secondPass) const { // Get languages built in this target. std::unordered_set<std::string> languages; - cmLinkImplementation const* impl = this->GetLinkImplementation(config); + cmLinkImplementation const* impl = + this->GetLinkImplementation(config, secondPass); assert(impl); - for (std::string const& li : impl->Languages) { - languages.insert(li); - } + languages.insert(impl->Languages.cbegin(), impl->Languages.cend()); // Add interface languages from linked targets. - cmTargetCollectLinkLanguages cll(this, config, languages, this); + // cmTargetCollectLinkLanguages cll(this, config, languages, this, + // secondPass); + cmTargetCollectLinkLanguages cll(this, config, languages, this, secondPass); for (cmLinkImplItem const& lib : impl->Libraries) { cll.Visit(lib); } // Store the transitive closure of languages. - for (std::string const& lang : languages) { - lc.Languages.push_back(lang); - } + cm::append(lc.Languages, languages); // Choose the language whose linker should be used. - if (this->GetProperty("HAS_CXX")) { - lc.LinkerLanguage = "CXX"; - } else if (const char* linkerLang = this->GetProperty("LINKER_LANGUAGE")) { - lc.LinkerLanguage = linkerLang; - } else { + if (secondPass || lc.LinkerLanguage.empty()) { // Find the language with the highest preference value. cmTargetSelectLinker tsl(this); // First select from the languages compiled directly in this target. for (std::string const& l : impl->Languages) { - tsl.Consider(l.c_str()); + tsl.Consider(l); } // Now consider languages that propagate from linked targets. @@ -2366,12 +2437,50 @@ void cmGeneratorTarget::ComputeLinkClosure(const std::string& config, std::string propagates = "CMAKE_" + lang + "_LINKER_PREFERENCE_PROPAGATES"; if (this->Makefile->IsOn(propagates)) { - tsl.Consider(lang.c_str()); + tsl.Consider(lang); } } lc.LinkerLanguage = tsl.Choose(); } + + return impl->HadLinkLanguageSensitiveCondition || + cll.GetHadLinkLanguageSensitiveCondition(); +} + +void cmGeneratorTarget::ComputeLinkClosure(const std::string& config, + LinkClosure& lc) const +{ + bool secondPass = false; + + { + LinkClosure linkClosure; + linkClosure.LinkerLanguage = this->LinkerLanguage; + + // Get languages built in this target. + secondPass = this->ComputeLinkClosure(config, linkClosure, false); + this->LinkerLanguage = linkClosure.LinkerLanguage; + if (!secondPass) { + lc = std::move(linkClosure); + } + } + + if (secondPass) { + LinkClosure linkClosure; + + this->ComputeLinkClosure(config, linkClosure, secondPass); + lc = std::move(linkClosure); + + // linker language must not be changed between the two passes + if (this->LinkerLanguage != lc.LinkerLanguage) { + std::ostringstream e; + e << "Evaluation of $<LINK_LANGUAGE:...> or $<LINK_LAND_AND_ID:...> " + "changes\nthe linker language for target \"" + << this->GetName() << "\" (from '" << this->LinkerLanguage << "' to '" + << lc.LinkerLanguage << "') which is invalid."; + cmSystemTools::Error(e.str()); + } + } } void cmGeneratorTarget::GetFullNameComponents( @@ -2492,11 +2601,11 @@ void cmGeneratorTarget::ComputeModuleDefinitionInfo( info.WindowsExportAllSymbols = this->Makefile->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") && this->GetPropertyAsBool("WINDOWS_EXPORT_ALL_SYMBOLS"); -#if defined(_WIN32) && !defined(CMAKE_BOOTSTRAP) +#if !defined(CMAKE_BOOTSTRAP) info.DefFileGenerated = info.WindowsExportAllSymbols || info.Sources.size() > 1; #else - // Our __create_def helper is only available on Windows. + // Our __create_def helper is not available during CMake bootstrap. info.DefFileGenerated = false; #endif if (info.DefFileGenerated) { @@ -2691,12 +2800,23 @@ void cmTargetTraceDependencies::FollowName(std::string const& name) if (i == this->NameMap.end() || i->first != name) { // Check if we know how to generate this file. cmSourcesWithOutput sources = this->Makefile->GetSourcesWithOutput(name); + // If we failed to find a target or source and we have a relative path, it + // might be a valid source if made relative to the current binary + // directory. + if (!sources.Target && !sources.Source && + !cmSystemTools::FileIsFullPath(name)) { + auto fullname = + cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name); + fullname = cmSystemTools::CollapseFullPath( + fullname, this->Makefile->GetHomeOutputDirectory()); + sources = this->Makefile->GetSourcesWithOutput(fullname); + } i = this->NameMap.emplace_hint(i, name, sources); } if (cmTarget* t = i->second.Target) { // The name is a byproduct of a utility target or a PRE_BUILD, PRE_LINK, or // POST_BUILD command. - this->GeneratorTarget->Target->AddUtility(t->GetName()); + this->GeneratorTarget->Target->AddUtility(t->GetName(), false); } if (cmSourceFile* sf = i->second.Source) { // For now only follow the dependency if the source file is not a @@ -2751,14 +2871,14 @@ bool cmTargetTraceDependencies::IsUtility(std::string const& dep) depLocation = cmSystemTools::CollapseFullPath(depLocation); tLocation = cmSystemTools::CollapseFullPath(tLocation); if (depLocation == tLocation) { - this->GeneratorTarget->Target->AddUtility(util); + this->GeneratorTarget->Target->AddUtility(util, false); return true; } } } else { // The original name of the dependency was not a full path. It // must name a target, so add the target-level dependency. - this->GeneratorTarget->Target->AddUtility(util); + this->GeneratorTarget->Target->AddUtility(util, false); return true; } } @@ -2786,7 +2906,7 @@ void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc) // this project. Add the target-level dependency to make // sure the executable is up to date before this custom // command possibly runs. - this->GeneratorTarget->Target->AddUtility(command); + this->GeneratorTarget->Target->AddUtility(command, true); } } @@ -2801,7 +2921,7 @@ void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc) } for (cmGeneratorTarget* target : targets) { - this->GeneratorTarget->Target->AddUtility(target->GetName()); + this->GeneratorTarget->Target->AddUtility(target->GetName(), true); } // Queue the custom command dependencies. @@ -3064,7 +3184,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( cmLinkImplementationLibraries const* impl = this->GetLinkImplementationLibraries(config); for (cmLinkImplItem const& lib : impl->Libraries) { - std::string libDir = cmSystemTools::CollapseFullPath(lib.AsStr()); + std::string libDir = cmSystemTools::CollapseFullPath( + lib.AsStr(), this->Makefile->GetHomeOutputDirectory()); static cmsys::RegularExpression frameworkCheck( "(.*\\.framework)(/Versions/[^/]+)?/[^/]+$"); @@ -3277,10 +3398,10 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( CM_FALLTHROUGH; } case cmPolicies::OLD: { - std::unique_ptr<TargetPropertyEntry> entry( - CreateTargetPropertyEntry(configProp)); + std::unique_ptr<TargetPropertyEntry> entry = + CreateTargetPropertyEntry(configProp); entries.emplace_back(EvaluateTargetPropertyEntry( - this, config, language, &dagChecker, entry.get())); + this, config, language, &dagChecker, *entry)); } break; case cmPolicies::NEW: case cmPolicies::REQUIRED_ALWAYS: @@ -3373,14 +3494,22 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, { "OBJCXX", ".objcxx.hxx" } }; - filename = cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(), - ".dir/cmake_pch", languageToExtension.at(language)); + filename = + cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(), ".dir"); + + if (this->GetGlobalGenerator()->IsMultiConfig()) { + filename = cmStrCat(filename, "/", config); + } + + filename = + cmStrCat(filename, "/cmake_pch", languageToExtension.at(language)); const std::string filename_tmp = cmStrCat(filename, ".tmp"); if (!pchReuseFrom) { auto pchPrologue = this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE"); auto pchEpilogue = this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE"); + std::string firstHeaderOnDisk; { cmGeneratedFileStream file( filename_tmp, false, @@ -3404,6 +3533,11 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, } else { file << "#include \"" << header_bt.Value << "\"\n"; } + + if (cmSystemTools::FileExists(header_bt.Value) && + firstHeaderOnDisk.empty()) { + firstHeaderOnDisk = header_bt.Value; + } } if (language == "CXX") { file << "#endif // __cplusplus\n"; @@ -3415,6 +3549,11 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, file << pchEpilogue << "\n"; } } + + if (!firstHeaderOnDisk.empty()) { + cmFileTimes::Copy(firstHeaderOnDisk, filename_tmp); + } + cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); } } @@ -3473,6 +3612,7 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config, cmGeneratedFileStream file(filename_tmp); file << "/* generated by CMake */\n"; } + cmFileTimes::Copy(pchHeader, filename_tmp); cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); } } @@ -3647,7 +3787,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( this->LinkOptionsEntries); AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language, - &dagChecker, entries); + &dagChecker, entries, + this->GetPolicyStatusCMP0099() != cmPolicies::NEW); processOptions(this, entries, result, uniqueOptions, debugOptions, "link options", OptionsParse::Shell); @@ -3779,10 +3920,10 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions( if (const char* 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.emplace_back(EvaluateTargetPropertyEntry( - this, config, language, &dagChecker, entry.get())); + std::unique_ptr<TargetPropertyEntry> entry = + CreateTargetPropertyEntry(option); + entries.emplace_back(EvaluateTargetPropertyEntry(this, config, language, + &dagChecker, *entry)); } } processOptions(this, entries, result, uniqueOptions, false, @@ -3902,7 +4043,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( this->LinkDirectoriesEntries); AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language, - &dagChecker, entries); + &dagChecker, entries, + this->GetPolicyStatusCMP0099() != cmPolicies::NEW); processLinkDirectories(this, entries, result, uniqueDirectories, debugDirectories); @@ -3933,14 +4075,15 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( if (const char* linkDepends = this->GetProperty("LINK_DEPENDS")) { std::vector<std::string> depends = cmExpandedList(linkDepends); for (const auto& depend : depends) { - std::unique_ptr<TargetPropertyEntry> entry( - CreateTargetPropertyEntry(depend)); - entries.emplace_back(EvaluateTargetPropertyEntry( - this, config, language, &dagChecker, entry.get())); + std::unique_ptr<TargetPropertyEntry> entry = + CreateTargetPropertyEntry(depend); + entries.emplace_back(EvaluateTargetPropertyEntry(this, config, language, + &dagChecker, *entry)); } } AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language, - &dagChecker, entries); + &dagChecker, entries, + this->GetPolicyStatusCMP0099() != cmPolicies::NEW); processOptions(this, entries, result, uniqueOptions, false, "link depends", OptionsParse::None); @@ -4126,8 +4269,8 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames( targetNames.Real += this->GetFrameworkVersion(); targetNames.Real += "/"; } - targetNames.Real += targetNames.Base; - targetNames.SharedObject = targetNames.Real; + targetNames.Real += targetNames.Base + suffix; + targetNames.SharedObject = targetNames.Real + suffix; } else { // The library's soname. this->ComputeVersionedName(targetNames.SharedObject, prefix, @@ -4302,7 +4445,15 @@ void cmGeneratorTarget::GetFullNameInternal( outBase += this->GetOutputName(config, artifact); // Append the per-configuration postfix. - outBase += configPostfix; + // When using Xcode, the postfix should be part of the suffix rather than the + // base, because the suffix ends up being used in Xcode's EXECUTABLE_SUFFIX + // attribute. + if (this->IsFrameworkOnApple() && + GetGlobalGenerator()->GetName() == "Xcode") { + targetSuffix = configPostfix.c_str(); + } else { + outBase += configPostfix; + } // Name shared libraries with their version number on some platforms. if (const char* soversion = this->GetProperty("SOVERSION")) { @@ -4720,9 +4871,9 @@ std::string intersect(const std::set<std::string>& s1, } void cmGeneratorTarget::CheckPropertyCompatibility( - cmComputeLinkInformation* info, const std::string& config) const + cmComputeLinkInformation& info, const std::string& config) const { - const cmComputeLinkInformation::ItemVector& deps = info->GetItems(); + const cmComputeLinkInformation::ItemVector& deps = info.GetItems(); std::set<std::string> emittedBools; static const std::string strBool = "COMPATIBLE_INTERFACE_BOOL"; @@ -5067,10 +5218,11 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, } std::string interfaceProperty = "INTERFACE_" + p; - std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter( - p == "POSITION_INDEPENDENT_CODE" ? new cmGeneratorExpressionInterpreter( - tgt->GetLocalGenerator(), config, tgt) - : nullptr); + std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter; + if (p == "POSITION_INDEPENDENT_CODE") { + genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>( + tgt->GetLocalGenerator(), config, tgt); + } for (cmGeneratorTarget const* theTarget : deps) { // An error should be reported if one dependency @@ -5217,32 +5369,41 @@ cmComputeLinkInformation* cmGeneratorTarget::GetLinkInformation( auto i = this->LinkInformation.find(key); if (i == this->LinkInformation.end()) { // Compute information for this configuration. - cmComputeLinkInformation* info = - new cmComputeLinkInformation(this, config); - if (!info || !info->Compute()) { - delete info; - info = nullptr; + auto info = cm::make_unique<cmComputeLinkInformation>(this, config); + if (info && !info->Compute()) { + info.reset(); } // Store the information for this configuration. - cmTargetLinkInformationMap::value_type entry(key, info); - i = this->LinkInformation.insert(entry).first; + i = this->LinkInformation.emplace(key, std::move(info)).first; - if (info) { - this->CheckPropertyCompatibility(info, config); + if (i->second) { + this->CheckPropertyCompatibility(*i->second, config); } } - return i->second; + return i->second.get(); } void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const { int patch; - this->GetTargetVersion(false, major, minor, patch); + this->GetTargetVersion("VERSION", major, minor, patch); +} + +void cmGeneratorTarget::GetTargetVersionFallback( + const std::string& property, const std::string& fallback_property, + int& major, int& minor, int& patch) const +{ + if (this->GetProperty(property)) { + this->GetTargetVersion(property, major, minor, patch); + } else { + this->GetTargetVersion(fallback_property, major, minor, patch); + } } -void cmGeneratorTarget::GetTargetVersion(bool soversion, int& major, - int& minor, int& patch) const +void cmGeneratorTarget::GetTargetVersion(const std::string& property, + int& major, int& minor, + int& patch) const { // Set the default values. major = 0; @@ -5251,9 +5412,7 @@ void cmGeneratorTarget::GetTargetVersion(bool soversion, int& major, assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY); - // Look for a VERSION or SOVERSION property. - const char* prop = soversion ? "SOVERSION" : "VERSION"; - if (const char* version = this->GetProperty(prop)) { + if (const char* version = this->GetProperty(property)) { // Try to parse the version number and store the results that were // successfully parsed. int parsed_major; @@ -5383,24 +5542,49 @@ void cmGeneratorTarget::ReportPropertyOrigin( areport); } +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); + if (dirId.String.empty()) { + lg = this->LocalGenerator; + return true; + } + if (cmLocalGenerator const* otherLG = + this->GlobalGenerator->FindLocalGenerator(dirId)) { + lg = otherLG; + return true; + } + } + return false; +} + void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names, cmListFileBacktrace const& bt, std::vector<cmLinkItem>& items) const { + cmLocalGenerator const* lg = this->LocalGenerator; for (std::string const& n : names) { + if (this->IsLinkLookupScope(n, lg)) { + continue; + } + std::string name = this->CheckCMP0004(n); if (name == this->GetName() || name.empty()) { continue; } - items.push_back(this->ResolveLinkItem(name, bt)); + items.push_back(this->ResolveLinkItem(name, bt, lg)); } } void cmGeneratorTarget::ExpandLinkItems( std::string const& prop, std::string const& value, std::string const& config, cmGeneratorTarget const* headTarget, bool usage_requirements_only, - std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition) const + std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition, + bool& hadLinkLanguageSensitiveCondition) const { + // Keep this logic in sync with ComputeLinkImplementationLibraries. cmGeneratorExpression ge; cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr); // The $<LINK_ONLY> expression may be in a link interface to specify private @@ -5410,19 +5594,28 @@ void cmGeneratorTarget::ExpandLinkItems( } std::vector<std::string> libs; std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); - cmExpandList( - cge->Evaluate(this->LocalGenerator, config, headTarget, &dagChecker, this), - libs); + cmExpandList(cge->Evaluate(this->LocalGenerator, config, headTarget, + &dagChecker, this, headTarget->LinkerLanguage), + libs); this->LookupLinkItems(libs, cge->GetBacktrace(), items); hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition(); + hadLinkLanguageSensitiveCondition = + cge->GetHadLinkLanguageSensitiveCondition(); } cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( const std::string& config, cmGeneratorTarget const* head) const { + return this->GetLinkInterface(config, head, false); +} + +cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( + const std::string& config, cmGeneratorTarget const* head, + bool secondPass) const +{ // Imported targets have their own link interface. if (this->IsImported()) { - return this->GetImportLinkInterface(config, head, false); + return this->GetImportLinkInterface(config, head, false, secondPass); } // Link interfaces are not supported for executables that do not @@ -5435,6 +5628,10 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( // Lookup any existing link interface for this configuration. cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config); + if (secondPass) { + hm.erase(head); + } + // If the link interface does not depend on the head target // then return the one we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { @@ -5449,7 +5646,7 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( if (!iface.AllDone) { iface.AllDone = true; if (iface.Exists) { - this->ComputeLinkInterface(config, iface, head); + this->ComputeLinkInterface(config, iface, head, secondPass); } } @@ -5460,6 +5657,13 @@ void cmGeneratorTarget::ComputeLinkInterface( const std::string& config, cmOptionalLinkInterface& iface, cmGeneratorTarget const* headTarget) const { + this->ComputeLinkInterface(config, iface, headTarget, false); +} + +void cmGeneratorTarget::ComputeLinkInterface( + const std::string& config, cmOptionalLinkInterface& iface, + cmGeneratorTarget const* headTarget, bool secondPass) const +{ if (iface.Explicit) { if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::STATIC_LIBRARY || @@ -5471,7 +5675,8 @@ void cmGeneratorTarget::ComputeLinkInterface( emitted.insert(lib); } if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - cmLinkImplementation const* impl = this->GetLinkImplementation(config); + cmLinkImplementation const* impl = + this->GetLinkImplementation(config, secondPass); for (cmLinkImplItem const& lib : impl->Libraries) { if (emitted.insert(lib).second) { if (lib.Target) { @@ -5501,7 +5706,7 @@ void cmGeneratorTarget::ComputeLinkInterface( if (this->LinkLanguagePropagatesToDependents()) { // Targets using this archive need its language runtime libraries. if (cmLinkImplementation const* impl = - this->GetLinkImplementation(config)) { + this->GetLinkImplementation(config, secondPass)) { iface.Languages = impl->Languages; } } @@ -5897,7 +6102,8 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( // The interface libraries have been explicitly set. this->ExpandLinkItems(linkIfaceProp, explicitLibraries, config, headTarget, usage_requirements_only, iface.Libraries, - iface.HadHeadSensitiveCondition); + iface.HadHeadSensitiveCondition, + iface.HadLinkLanguageSensitiveCondition); } else if (!cmp0022NEW) // If CMP0022 is NEW then the plain tll signature sets the // INTERFACE_LINK_LIBRARIES, so if we get here then the project @@ -5917,9 +6123,11 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( static const std::string newProp = "INTERFACE_LINK_LIBRARIES"; if (const char* newExplicitLibraries = this->GetProperty(newProp)) { bool hadHeadSensitiveConditionDummy = false; + bool hadLinkLanguageSensitiveConditionDummy = false; this->ExpandLinkItems(newProp, newExplicitLibraries, config, headTarget, usage_requirements_only, ifaceLibs, - hadHeadSensitiveConditionDummy); + hadHeadSensitiveConditionDummy, + hadLinkLanguageSensitiveConditionDummy); } if (ifaceLibs != iface.Libraries) { std::string oldLibraries = cmJoin(impl->Libraries, ";"); @@ -5956,7 +6164,7 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( const std::string& config, cmGeneratorTarget const* headTarget, - bool usage_requirements_only) const + bool usage_requirements_only, bool secondPass) const { cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config); if (!info) { @@ -5969,6 +6177,10 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config) : this->GetHeadToLinkInterfaceMap(config)); + if (secondPass) { + hm.erase(headTarget); + } + // If the link interface does not depend on the head target // then return the one we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { @@ -5982,7 +6194,8 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( cmExpandList(info->Languages, iface.Languages); this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config, headTarget, usage_requirements_only, iface.Libraries, - iface.HadHeadSensitiveCondition); + iface.HadHeadSensitiveCondition, + iface.HadLinkLanguageSensitiveCondition); std::vector<std::string> deps = cmExpandedList(info->SharedDeps); this->LookupLinkItems(deps, cmListFileBacktrace(), iface.SharedDeps); } @@ -6187,6 +6400,12 @@ cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap( const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( const std::string& config) const { + return this->GetLinkImplementation(config, false); +} + +const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( + const std::string& config, bool secondPass) const +{ // There is no link implementation for imported targets. if (this->IsImported()) { return nullptr; @@ -6194,6 +6413,9 @@ const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( std::string CONFIG = cmSystemTools::UpperCase(config); cmOptionalLinkImplementation& impl = this->LinkImplMap[CONFIG][this]; + if (secondPass) { + impl = cmOptionalLinkImplementation(); + } if (!impl.LibrariesDone) { impl.LibrariesDone = true; this->ComputeLinkImplementationLibraries(config, impl, this); @@ -6330,6 +6552,21 @@ std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const return lib; } +bool cmGeneratorTarget::IsDeprecated() const +{ + const char* deprecation = this->GetProperty("DEPRECATION"); + return deprecation && *deprecation; +} + +std::string cmGeneratorTarget::GetDeprecation() const +{ + // find DEPRECATION property + if (const char* deprecation = this->GetProperty("DEPRECATION")) { + return deprecation; + } + return std::string(); +} + void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages, const std::string& config) const { @@ -6379,8 +6616,7 @@ bool cmGeneratorTarget::IsCSharpOnly() const this->GetType() != cmStateEnums::EXECUTABLE) { return false; } - std::set<std::string> languages; - this->GetLanguages(languages, ""); + std::set<std::string> languages = this->GetAllConfigCompileLanguages(); // Consider an explicit linker language property, but *not* the // computed linker language that may depend on linked targets. const char* linkLang = this->GetProperty("LINKER_LANGUAGE"); @@ -6462,6 +6698,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( const std::string& config, cmOptionalLinkImplementation& impl, cmGeneratorTarget const* head) const { + cmLocalGenerator const* lg = this->LocalGenerator; cmStringRange entryRange = this->Target->GetLinkImplementationEntries(); cmBacktraceRange btRange = this->Target->GetLinkImplementationBacktraces(); cmBacktraceRange::const_iterator btIt = btRange.begin(); @@ -6470,18 +6707,27 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( end = entryRange.end(); le != end; ++le, ++btIt) { std::vector<std::string> llibs; + // Keep this logic in sync with ExpandLinkItems. cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr, nullptr); cmGeneratorExpression ge(*btIt); std::unique_ptr<cmCompiledGeneratorExpression> const cge = ge.Parse(*le); std::string const& evaluated = - cge->Evaluate(this->LocalGenerator, config, head, &dagChecker); + cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr, + this->LinkerLanguage); cmExpandList(evaluated, llibs); if (cge->GetHadHeadSensitiveCondition()) { impl.HadHeadSensitiveCondition = true; } + if (cge->GetHadLinkLanguageSensitiveCondition()) { + impl.HadLinkLanguageSensitiveCondition = true; + } for (std::string const& lib : llibs) { + if (this->IsLinkLookupScope(lib, lg)) { + continue; + } + // Skip entries that resolve to the target itself or are empty. std::string name = this->CheckCMP0004(lib); if (name == this->GetName() || name.empty()) { @@ -6516,7 +6762,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( } // The entry is meant for this configuration. - impl.Libraries.emplace_back(this->ResolveLinkItem(name, *btIt), + impl.Libraries.emplace_back(this->ResolveLinkItem(name, *btIt, lg), evaluated != *le); } @@ -6553,38 +6799,16 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference( std::string const& name) const { - cmLocalGenerator const* lg = this->LocalGenerator; - std::string const* lookupName = &name; - - // When target_link_libraries() is called with a LHS target that is - // not created in the calling directory it adds a directory id suffix - // that we can use to look up the calling directory. It is that scope - // in which the item name is meaningful. This case is relatively rare - // so we allocate a separate string only when the directory id is present. - std::string::size_type pos = name.find(CMAKE_DIRECTORY_ID_SEP); - std::string plainName; - if (pos != std::string::npos) { - // We will look up the plain name without the directory id suffix. - plainName = name.substr(0, pos); - - // We will look up in the scope of the directory id. - // If we do not recognize the id then leave the original - // syntax in place to produce an indicative error later. - cmDirectoryId const dirId = - name.substr(pos + sizeof(CMAKE_DIRECTORY_ID_SEP) - 1); - if (cmLocalGenerator const* otherLG = - this->GlobalGenerator->FindLocalGenerator(dirId)) { - lg = otherLG; - lookupName = &plainName; - } - } + return this->ResolveTargetReference(name, this->LocalGenerator); +} +cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference( + std::string const& name, cmLocalGenerator const* lg) const +{ TargetOrString resolved; - if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(*lookupName)) { + if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(name)) { resolved.Target = tgt; - } else if (lookupName == &plainName) { - resolved.String = std::move(plainName); } else { resolved.String = name; } @@ -6595,10 +6819,30 @@ cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference( cmLinkItem cmGeneratorTarget::ResolveLinkItem( std::string const& name, cmListFileBacktrace const& bt) const { - TargetOrString resolved = this->ResolveTargetReference(name); + return this->ResolveLinkItem(name, bt, this->LocalGenerator); +} + +cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name, + cmListFileBacktrace const& bt, + cmLocalGenerator const* lg) const +{ + TargetOrString resolved = this->ResolveTargetReference(name, lg); if (!resolved.Target) { - return cmLinkItem(resolved.String, bt); + return cmLinkItem(resolved.String, false, bt); + } + + // Check deprecation, issue message with `bt` backtrace. + if (resolved.Target->IsDeprecated()) { + std::ostringstream w; + /* clang-format off */ + w << + "The library that is being linked to, " << resolved.Target->GetName() << + ", is marked as being deprecated by the owner. The message provided by " + "the developer is: \n" << resolved.Target->GetDeprecation() << "\n"; + /* clang-format on */ + this->LocalGenerator->GetCMakeInstance()->IssueMessage( + MessageType::AUTHOR_WARNING, w.str(), bt); } // Skip targets that will not really be linked. This is probably a @@ -6606,10 +6850,10 @@ cmLinkItem cmGeneratorTarget::ResolveLinkItem( // within the project. if (resolved.Target->GetType() == cmStateEnums::EXECUTABLE && !resolved.Target->IsExecutableWithExports()) { - return cmLinkItem(resolved.Target->GetName(), bt); + return cmLinkItem(resolved.Target->GetName(), false, bt); } - return cmLinkItem(resolved.Target, bt); + return cmLinkItem(resolved.Target, false, bt); } std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 493eafc..12d30c5 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -7,6 +7,7 @@ #include <cstddef> #include <map> +#include <memory> #include <set> #include <string> #include <unordered_map> @@ -45,7 +46,7 @@ public: bool IsImported() const; bool IsImportedGloballyVisible() const; - const char* GetLocation(const std::string& config) const; + const std::string& GetLocation(const std::string& config) const; std::vector<cmCustomCommand> const& GetPreBuildCommands() const; std::vector<cmCustomCommand> const& GetPreLinkCommands() const; @@ -64,7 +65,7 @@ public: /** Get the location of the target in the build tree with a placeholder referencing the configuration in the native build system. This location is suitable for use as the LOCATION target property. */ - const char* GetLocationForBuild() const; + const std::string& GetLocationForBuild() const; cmComputeLinkInformation* GetLinkInformation( const std::string& config) const; @@ -125,7 +126,7 @@ public: struct AllConfigSource { - cmSourceFile const* Source; + cmSourceFile* Source; cmGeneratorTarget::SourceKind Kind; std::vector<size_t> Configs; }; @@ -134,6 +135,10 @@ public: per-source configurations assigned. */ std::vector<AllConfigSource> const& GetAllConfigSources() const; + /** Get all languages used to compile sources in any configuration. + This excludes the languages of objects from object libraries. */ + std::set<std::string> GetAllConfigCompileLanguages() const; + void GetObjectSources(std::vector<cmSourceFile const*>&, const std::string& config) const; const std::string& GetObjectName(cmSourceFile const* file); @@ -245,6 +250,13 @@ public: std::string GetAppBundleDirectory(const std::string& config, BundleDirectoryLevel level) const; + /** Return whether this target is marked as deprecated by the + maintainer */ + bool IsDeprecated() const; + + /** Returns the deprecation message provided by the maintainer */ + std::string GetDeprecation() const; + /** Return whether this target is an executable Bundle, a framework or CFBundle on Apple. */ bool IsBundleOnApple() const; @@ -274,11 +286,12 @@ public: /** Return the install name directory for the target in the * install tree. For example: "\@rpath/" or "\@loader_path/". */ - std::string GetInstallNameDirForInstallTree() const; + std::string GetInstallNameDirForInstallTree( + const std::string& config, const std::string& installPrefix) const; cmListFileBacktrace GetBacktrace() const; - std::set<BT<std::string>> const& GetUtilities() const; + std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const; bool LinkLanguagePropagatesToDependents() const { @@ -344,7 +357,6 @@ public: }; LinkClosure const* GetLinkClosure(const std::string& config) const; - void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const; cmLinkImplementation const* GetLinkImplementation( const std::string& config) const; @@ -365,9 +377,14 @@ public: cmGeneratorTarget* Target = nullptr; }; TargetOrString ResolveTargetReference(std::string const& name) const; + TargetOrString ResolveTargetReference(std::string const& name, + cmLocalGenerator const* lg) const; cmLinkItem ResolveLinkItem(std::string const& name, cmListFileBacktrace const& bt) const; + cmLinkItem ResolveLinkItem(std::string const& name, + cmListFileBacktrace const& bt, + cmLocalGenerator const* lg) const; // Compute the set of languages compiled by the target. This is // computed every time it is called because the languages can change @@ -571,6 +588,9 @@ public: /** Get target file postfix */ std::string GetFilePostfix(const std::string& config) const; + /** Get framework multi-config-specific postfix */ + std::string GetFrameworkMultiConfigPostfix(const std::string& config) const; + /** Clears cached meta data for local and external source files. * The meta data will be recomputed on demand. */ @@ -701,7 +721,8 @@ public: std::string EvaluateInterfaceProperty( std::string const& prop, cmGeneratorExpressionContext* context, - cmGeneratorExpressionDAGChecker* dagCheckerParent) const; + cmGeneratorExpressionDAGChecker* dagCheckerParent, + bool usage_requirements_only = true) const; bool HaveInstallTreeRPATH(const std::string& config) const; @@ -736,14 +757,22 @@ public: void GetTargetVersion(int& major, int& minor) const; /** Get the target major, minor, and patch version numbers - interpreted from the VERSION or SOVERSION property. Version 0 + interpreted from the given property. Version 0 is returned if the property is not set or cannot be parsed. */ - void GetTargetVersion(bool soversion, int& major, int& minor, + void GetTargetVersion(std::string const& property, int& major, int& minor, int& patch) const; + /** Get the target major, minor, and patch version numbers + interpreted from the given property and if empty use the + fallback property. Version 0 is returned if the property is + not set or cannot be parsed. */ + void GetTargetVersionFallback(const std::string& property, + const std::string& fallback_property, + int& major, int& minor, int& patch) const; + std::string GetFortranModuleDirectory(std::string const& working_dir) const; - const char* GetSourcesProperty() const; + const std::string& GetSourcesProperty() const; private: void AddSourceCommon(const std::string& src, bool before = false); @@ -760,6 +789,7 @@ private: }; using SourceEntriesType = std::map<cmSourceFile const*, SourceEntry>; SourceEntriesType SourceDepends; + mutable std::set<std::string> VisitedConfigsForObjects; mutable std::map<cmSourceFile const*, std::string> Objects; std::set<cmSourceFile const*> ExplicitObjectName; mutable std::map<std::string, std::vector<std::string>> SystemIncludesCache; @@ -788,6 +818,7 @@ private: std::string& outPrefix, std::string& outBase, std::string& outSuffix) const; + mutable std::string LinkerLanguage; using LinkClosureMapType = std::map<std::string, LinkClosure>; mutable LinkClosureMapType LinkClosureMap; @@ -816,12 +847,16 @@ private: mutable std::map<std::string, CompatibleInterfaces> CompatibleInterfacesMap; using cmTargetLinkInformationMap = - std::map<std::string, cmComputeLinkInformation*>; + std::map<std::string, std::unique_ptr<cmComputeLinkInformation>>; mutable cmTargetLinkInformationMap LinkInformation; - void CheckPropertyCompatibility(cmComputeLinkInformation* info, + void CheckPropertyCompatibility(cmComputeLinkInformation& info, const std::string& config) const; + void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const; + bool ComputeLinkClosure(const std::string& config, LinkClosure& lc, + bool secondPass) const; + struct LinkImplClosure : public std::vector<cmGeneratorTarget const*> { bool Done = false; @@ -840,6 +875,17 @@ private: std::string GetLinkInterfaceDependentStringAsBoolProperty( const std::string& p, const std::string& config) const; + friend class cmTargetCollectLinkLanguages; + cmLinkInterface const* GetLinkInterface(const std::string& config, + const cmGeneratorTarget* headTarget, + bool secondPass) const; + void ComputeLinkInterface(const std::string& config, + cmOptionalLinkInterface& iface, + const cmGeneratorTarget* head, + bool secondPass) const; + cmLinkImplementation const* GetLinkImplementation(const std::string& config, + bool secondPass) const; + // Cache import information from properties for each configuration. struct ImportInfo { @@ -866,9 +912,10 @@ private: the link dependencies of this target. */ std::string CheckCMP0004(std::string const& item) const; - cmLinkInterface const* GetImportLinkInterface( - const std::string& config, const cmGeneratorTarget* head, - bool usage_requirements_only) const; + cmLinkInterface const* GetImportLinkInterface(const std::string& config, + const cmGeneratorTarget* head, + bool usage_requirements_only, + bool secondPass = false) const; using KindedSourcesMapType = std::map<std::string, KindedSources>; mutable KindedSourcesMapType KindedSourcesMap; @@ -880,16 +927,20 @@ private: mutable std::unordered_map<std::string, bool> MaybeInterfacePropertyExists; bool MaybeHaveInterfaceProperty(std::string const& prop, - cmGeneratorExpressionContext* context) const; - - std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries; - std::vector<TargetPropertyEntry*> CompileOptionsEntries; - std::vector<TargetPropertyEntry*> CompileFeaturesEntries; - std::vector<TargetPropertyEntry*> CompileDefinitionsEntries; - std::vector<TargetPropertyEntry*> LinkOptionsEntries; - std::vector<TargetPropertyEntry*> LinkDirectoriesEntries; - std::vector<TargetPropertyEntry*> PrecompileHeadersEntries; - std::vector<TargetPropertyEntry*> SourceEntries; + cmGeneratorExpressionContext* context, + bool usage_requirements_only) const; + + using TargetPropertyEntryVector = + std::vector<std::unique_ptr<TargetPropertyEntry>>; + + TargetPropertyEntryVector IncludeDirectoriesEntries; + TargetPropertyEntryVector CompileOptionsEntries; + TargetPropertyEntryVector CompileFeaturesEntries; + TargetPropertyEntryVector CompileDefinitionsEntries; + TargetPropertyEntryVector LinkOptionsEntries; + TargetPropertyEntryVector LinkDirectoriesEntries; + TargetPropertyEntryVector PrecompileHeadersEntries; + TargetPropertyEntryVector SourceEntries; mutable std::set<std::string> LinkImplicitNullProperties; mutable std::map<std::string, std::string> PchHeaders; mutable std::map<std::string, std::string> PchSources; @@ -900,12 +951,16 @@ private: std::unordered_set<std::string> UnityBatchedSourceFiles; + bool IsLinkLookupScope(std::string const& n, + cmLocalGenerator const*& lg) const; + void ExpandLinkItems(std::string const& prop, std::string const& value, std::string const& config, const cmGeneratorTarget* headTarget, bool usage_requirements_only, std::vector<cmLinkItem>& items, - bool& hadHeadSensitiveCondition) const; + bool& hadHeadSensitiveCondition, + bool& hadLinkLanguageSensitiveCondition) const; void LookupLinkItems(std::vector<std::string> const& names, cmListFileBacktrace const& bt, std::vector<cmLinkItem>& items) const; diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx index 7d91a75..811421a 100644 --- a/Source/cmGetFilenameComponentCommand.cxx +++ b/Source/cmGetFilenameComponentCommand.cxx @@ -120,11 +120,11 @@ bool cmGetFilenameComponentCommand(std::vector<std::string> const& args, if (args.size() >= 4 && args.back() == "CACHE") { if (!programArgs.empty() && !storeArgs.empty()) { status.GetMakefile().AddCacheDefinition( - storeArgs, programArgs.c_str(), "", + storeArgs, programArgs, "", args[2] == "PATH" ? cmStateEnums::FILEPATH : cmStateEnums::STRING); } status.GetMakefile().AddCacheDefinition( - args.front(), result.c_str(), "", + args.front(), result, "", args[2] == "PATH" ? cmStateEnums::FILEPATH : cmStateEnums::STRING); } else { if (!programArgs.empty() && !storeArgs.empty()) { diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index 8e4352e..6470ea1 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -113,7 +113,7 @@ void cmGhsMultiTargetGenerator::Generate() // Tell the global generator the name of the project file this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME", - this->Name.c_str()); + this->Name); this->GeneratorTarget->Target->SetProperty( "GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType)); @@ -180,15 +180,12 @@ void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config, auto i = this->FlagsByLanguage.find(language); if (i == this->FlagsByLanguage.end()) { std::string flags; - const char* lang = language.c_str(); - - this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, lang, - config); - - this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget, lang, - config); + this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, + language, config); + this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget, + language, config); this->LocalGenerator->AddVisibilityPresetFlags( - flags, this->GeneratorTarget, lang); + flags, this->GeneratorTarget, language); // Append old-style preprocessor definition flags. if (this->Makefile->GetDefineFlags() != " ") { @@ -197,8 +194,8 @@ void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config, } // Add target-specific flags. - this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, lang, - config); + this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, + language, config); std::map<std::string, std::string>::value_type entry(language, flags); i = this->FlagsByLanguage.insert(entry).first; @@ -211,13 +208,12 @@ std::string cmGhsMultiTargetGenerator::GetDefines(const std::string& language, auto i = this->DefinesByLanguage.find(language); if (i == this->DefinesByLanguage.end()) { std::set<std::string> defines; - const char* lang = language.c_str(); // Add preprocessor definitions for this target and configuration. this->LocalGenerator->GetTargetDefines(this->GeneratorTarget, config, language, defines); std::string definesString; - this->LocalGenerator->JoinDefines(defines, definesString, lang); + this->LocalGenerator->JoinDefines(defines, definesString, language); std::map<std::string, std::string>::value_type entry(language, definesString); @@ -235,7 +231,7 @@ void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream& fout, if (!flagsByLangI->second.empty()) { std::vector<std::string> ghsCompFlags = cmSystemTools::ParseArguments(flagsByLangI->second); - for (auto& f : ghsCompFlags) { + for (const std::string& f : ghsCompFlags) { fout << " " << f << std::endl; } } @@ -279,10 +275,10 @@ void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout, std::string frameworkPath; std::string linkPath; - std::unique_ptr<cmLinkLineComputer> linkLineComputer( + std::unique_ptr<cmLinkLineComputer> linkLineComputer = this->GetGlobalGenerator()->CreateLinkLineComputer( this->LocalGenerator, - this->LocalGenerator->GetStateSnapshot().GetDirectory())); + this->LocalGenerator->GetStateSnapshot().GetDirectory()); this->LocalGenerator->GetTargetFlags( linkLineComputer.get(), config, linkLibraries, flags, linkFlags, @@ -290,14 +286,14 @@ void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout, // write out link options std::vector<std::string> lopts = cmSystemTools::ParseArguments(linkFlags); - for (auto& l : lopts) { + for (const std::string& l : lopts) { fout << " " << l << std::endl; } // write out link search paths // must be quoted for paths that contain spaces std::vector<std::string> lpath = cmSystemTools::ParseArguments(linkPath); - for (auto& l : lpath) { + for (const std::string& l : lpath) { fout << " -L\"" << l << "\"" << std::endl; } @@ -307,7 +303,7 @@ void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout, std::vector<std::string> llibs = cmSystemTools::ParseArguments(linkLibraries); - for (auto& l : llibs) { + for (const std::string& l : llibs) { if (l.compare(0, 2, "-l") == 0) { fout << " \"" << l << "\"" << std::endl; } else { @@ -463,7 +459,7 @@ void cmGhsMultiTargetGenerator::WriteSourceProperty( const char* prop = sf->GetProperty(propName); if (prop) { std::vector<std::string> list = cmExpandedList(prop); - for (auto& p : list) { + for (const std::string& p : list) { fout << " " << propFlag << p << std::endl; } } @@ -483,7 +479,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj) /* for each source file assign it to its group */ std::map<std::string, std::vector<cmSourceFile*>> groupFiles; std::set<std::string> groupNames; - for (auto& sf : sources) { + for (cmSourceFile* sf : sources) { cmSourceGroup* sourceGroup = this->Makefile->FindSourceGroup(sf->ResolveFullPath(), sourceGroups); std::string gn = sourceGroup->GetFullName(); @@ -730,7 +726,7 @@ bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp() } std::vector<cmSourceFile*> sources; this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName); - for (auto& sf : sources) { + for (const cmSourceFile* sf : sources) { if ("int" == sf->GetExtension()) { return true; } diff --git a/Source/cmGlobVerificationManager.cxx b/Source/cmGlobVerificationManager.cxx index 4817773..9ac5cd5 100644 --- a/Source/cmGlobVerificationManager.cxx +++ b/Source/cmGlobVerificationManager.cxx @@ -38,6 +38,8 @@ bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path) << cmVersion::GetMajorVersion() << "." << cmVersion::GetMinorVersion() << "\n"; + verifyScriptFile << "cmake_policy(SET CMP0009 NEW)\n"; + for (auto const& i : this->Cache) { CacheEntryKey k = std::get<0>(i); CacheEntryValue v = std::get<1>(i); diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx index 51d681d..06943e7 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.cxx +++ b/Source/cmGlobalBorlandMakefileGenerator.cxx @@ -2,6 +2,10 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalBorlandMakefileGenerator.h" +#include <utility> + +#include <cm/memory> + #include "cmDocumentationEntry.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" @@ -35,15 +39,14 @@ void cmGlobalBorlandMakefileGenerator::EnableLanguage( } //! Create a local generator appropriate to this Global Generator -cmLocalGenerator* cmGlobalBorlandMakefileGenerator::CreateLocalGenerator( - cmMakefile* mf) +std::unique_ptr<cmLocalGenerator> +cmGlobalBorlandMakefileGenerator::CreateLocalGenerator(cmMakefile* mf) { - cmLocalUnixMakefileGenerator3* lg = - new cmLocalUnixMakefileGenerator3(this, mf); + auto lg = cm::make_unique<cmLocalUnixMakefileGenerator3>(this, mf); lg->SetMakefileVariableSize(32); lg->SetMakeCommandEscapeTargetTwice(true); lg->SetBorlandMakeCurlyHack(true); - return lg; + return std::unique_ptr<cmLocalGenerator>(std::move(lg)); } void cmGlobalBorlandMakefileGenerator::GetDocumentation( diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h index da04743..9af0eac 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.h +++ b/Source/cmGlobalBorlandMakefileGenerator.h @@ -4,6 +4,7 @@ #define cmGlobalBorlandMakefileGenerator_h #include <iosfwd> +#include <memory> #include "cmGlobalNMakeMakefileGenerator.h" @@ -16,10 +17,10 @@ class cmGlobalBorlandMakefileGenerator : public cmGlobalUnixMakefileGenerator3 { public: cmGlobalBorlandMakefileGenerator(cmake* cm); - static cmGlobalGeneratorFactory* NewFactory() + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() { - return new cmGlobalGeneratorSimpleFactory< - cmGlobalBorlandMakefileGenerator>(); + return std::unique_ptr<cmGlobalGeneratorFactory>( + new cmGlobalGeneratorSimpleFactory<cmGlobalBorlandMakefileGenerator>()); } //! Get the name for the generator. @@ -33,7 +34,8 @@ public: static void GetDocumentation(cmDocumentationEntry& entry); //! Create a local generator appropriate to this Global Generator - cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override; + std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( + cmMakefile* mf) override; /** * Try to determine system information such as shared library diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx index 9fa4467..e04eef1 100644 --- a/Source/cmGlobalCommonGenerator.cxx +++ b/Source/cmGlobalCommonGenerator.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalCommonGenerator.h" +#include <memory> #include <utility> #include "cmGeneratorTarget.h" @@ -24,15 +25,15 @@ std::map<std::string, cmGlobalCommonGenerator::DirectoryTarget> cmGlobalCommonGenerator::ComputeDirectoryTargets() const { std::map<std::string, DirectoryTarget> dirTargets; - for (cmLocalGenerator* lg : this->LocalGenerators) { + for (const auto& lg : this->LocalGenerators) { std::string const& currentBinaryDir( lg->GetStateSnapshot().GetDirectory().GetCurrentBinary()); DirectoryTarget& dirTarget = dirTargets[currentBinaryDir]; - dirTarget.LG = lg; + dirTarget.LG = lg.get(); // The directory-level rule should depend on the target-level rules // for all targets in the directory. - for (auto gt : lg->GetGeneratorTargets()) { + for (const auto& gt : lg->GetGeneratorTargets()) { cmStateEnums::TargetType const type = gt->GetType(); if (type != cmStateEnums::EXECUTABLE && type != cmStateEnums::STATIC_LIBRARY && @@ -43,7 +44,7 @@ cmGlobalCommonGenerator::ComputeDirectoryTargets() const continue; } DirectoryTarget::Target t; - t.GT = gt; + t.GT = gt.get(); if (const char* exclude = gt->GetProperty("EXCLUDE_FROM_ALL")) { if (cmIsOn(exclude)) { // This target has been explicitly excluded. diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 09fb87d..0b9a3e5 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -7,9 +7,13 @@ #include <cstdio> #include <cstdlib> #include <cstring> +#include <functional> #include <initializer_list> #include <iterator> #include <sstream> +#include <utility> + +#include <cm/memory> #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" @@ -31,6 +35,7 @@ #include "cmGeneratorTarget.h" #include "cmInstallGenerator.h" #include "cmLinkLineComputer.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMSVC60LinkLineComputer.h" #include "cmMakefile.h" @@ -121,6 +126,7 @@ Json::Value cmGlobalGenerator::GetJson() const { Json::Value generator = Json::objectValue; generator["name"] = this->GetName(); + generator["multiConfig"] = this->IsMultiConfig(); return generator; } #endif @@ -165,7 +171,7 @@ bool cmGlobalGenerator::SetGeneratorPlatform(std::string const& p, return false; } -bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts, +bool cmGlobalGenerator::SetGeneratorToolset(std::string const& ts, bool, cmMakefile* mf) { if (ts.empty()) { @@ -256,16 +262,17 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang, } } -void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen) +void cmGlobalGenerator::AddBuildExportSet( + std::unique_ptr<cmExportBuildFileGenerator> gen) { - this->BuildExportSets[gen->GetMainExportFileName()] = gen; + this->BuildExportSets[gen->GetMainExportFileName()] = std::move(gen); } void cmGlobalGenerator::AddBuildExportExportSet( - cmExportBuildFileGenerator* gen) + std::unique_ptr<cmExportBuildFileGenerator> gen) { - this->BuildExportSets[gen->GetMainExportFileName()] = gen; - this->BuildExportExportSets[gen->GetMainExportFileName()] = gen; + this->BuildExportExportSets[gen->GetMainExportFileName()] = gen.get(); + this->AddBuildExportSet(std::move(gen)); } bool cmGlobalGenerator::GenerateImportFile(const std::string& file) @@ -275,13 +282,11 @@ bool cmGlobalGenerator::GenerateImportFile(const std::string& file) bool result = it->second->GenerateImportFile(); if (!this->ConfigureDoneCMP0026AndCMP0024) { - for (cmMakefile* m : this->Makefiles) { - m->RemoveExportBuildFileGeneratorCMP0024(it->second); + for (const auto& m : this->Makefiles) { + m->RemoveExportBuildFileGeneratorCMP0024(it->second.get()); } } - delete it->second; - it->second = nullptr; this->BuildExportSets.erase(it); return result; } @@ -295,8 +300,8 @@ void cmGlobalGenerator::ForceLinkerLanguages() bool cmGlobalGenerator::CheckTargetsForMissingSources() const { bool failed = false; - for (cmLocalGenerator* localGen : this->LocalGenerators) { - for (cmGeneratorTarget* target : localGen->GetGeneratorTargets()) { + for (const auto& localGen : this->LocalGenerators) { + for (const auto& target : localGen->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET || target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY || target->GetType() == cmStateEnums::TargetType::UTILITY || @@ -335,8 +340,8 @@ bool cmGlobalGenerator::CheckTargetsForType() const return false; } bool failed = false; - for (cmLocalGenerator* generator : this->LocalGenerators) { - for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) { + for (const auto& generator : this->LocalGenerators) { + for (const auto& target : generator->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::EXECUTABLE && target->GetPropertyAsBool("WIN32_EXECUTABLE")) { std::vector<std::string> const& configs = @@ -363,8 +368,8 @@ bool cmGlobalGenerator::CheckTargetsForPchCompilePdb() const return false; } bool failed = false; - for (cmLocalGenerator* generator : this->LocalGenerators) { - for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) { + for (const auto& generator : this->LocalGenerators) { + for (const auto& target : generator->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET || target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY || target->GetType() == cmStateEnums::TargetType::UTILITY || @@ -441,8 +446,8 @@ bool cmGlobalGenerator::FindMakeProgram(cmMakefile* mf) cmSystemTools::GetShortPath(makeProgram, makeProgram); cmSystemTools::SplitProgramPath(makeProgram, dir, file); makeProgram = cmStrCat(dir, '/', saveFile); - mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", makeProgram.c_str(), - "make program", cmStateEnums::FILEPATH); + mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", makeProgram, "make program", + cmStateEnums::FILEPATH); } return true; } @@ -650,7 +655,7 @@ void cmGlobalGenerator::EnableLanguage( // Tell the generator about the toolset, if any. std::string toolset = mf->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET"); - if (!this->SetGeneratorToolset(toolset, mf)) { + if (!this->SetGeneratorToolset(toolset, false, mf)) { cmSystemTools::SetFatalErrorOccured(); return; } @@ -1199,13 +1204,12 @@ void cmGlobalGenerator::ClearEnabledLanguages() void cmGlobalGenerator::CreateLocalGenerators() { this->LocalGeneratorSearchIndex.clear(); - cmDeleteAll(this->LocalGenerators); this->LocalGenerators.clear(); this->LocalGenerators.reserve(this->Makefiles.size()); - for (cmMakefile* m : this->Makefiles) { - cmLocalGenerator* lg = this->CreateLocalGenerator(m); - this->LocalGenerators.push_back(lg); - this->IndexLocalGenerator(lg); + for (const auto& m : this->Makefiles) { + auto lg = this->CreateLocalGenerator(m.get()); + this->IndexLocalGenerator(lg.get()); + this->LocalGenerators.push_back(std::move(lg)); } } @@ -1221,9 +1225,10 @@ void cmGlobalGenerator::Configure() snapshot.GetDirectory().SetCurrentBinary( this->CMakeInstance->GetHomeOutputDirectory()); - cmMakefile* dirMf = new cmMakefile(this, snapshot); + auto dirMfu = cm::make_unique<cmMakefile>(this, snapshot); + auto dirMf = dirMfu.get(); + this->Makefiles.push_back(std::move(dirMfu)); dirMf->SetRecursionDepth(this->RecursionDepth); - this->Makefiles.push_back(dirMf); this->IndexMakefile(dirMf); this->BinaryDirectories.insert( @@ -1241,11 +1246,11 @@ void cmGlobalGenerator::Configure() std::vector<GlobalTargetInfo> globalTargets; this->CreateDefaultGlobalTargets(globalTargets); - for (cmMakefile* mf : this->Makefiles) { + for (const auto& mf : this->Makefiles) { auto& targets = mf->GetTargets(); for (GlobalTargetInfo const& globalTarget : globalTargets) { targets.emplace(globalTarget.Name, - this->CreateGlobalTarget(globalTarget, mf)); + this->CreateGlobalTarget(globalTarget, mf.get())); } } } @@ -1258,10 +1263,6 @@ void cmGlobalGenerator::Configure() "number of local generators", cmStateEnums::INTERNAL); - // check for link libraries and include directories containing "NOTFOUND" - // and for infinite loops - this->CheckTargetProperties(); - if (this->CMakeInstance->GetWorkingMode() == cmake::NORMAL_MODE) { std::ostringstream msg; if (cmSystemTools::GetErrorOccuredFlag()) { @@ -1284,6 +1285,10 @@ void cmGlobalGenerator::Configure() void cmGlobalGenerator::CreateGenerationObjects(TargetTypes targetTypes) { this->CreateLocalGenerators(); + // Commit side effects only if we are actually generating + if (this->GetConfigureDoneCMP0026()) { + this->CheckTargetProperties(); + } this->CreateGeneratorTargets(targetTypes); this->ComputeBuildFileGenerators(); } @@ -1294,8 +1299,11 @@ void cmGlobalGenerator::CreateImportedGenerationObjects( { this->CreateGenerationObjects(ImportedOnly); auto const mfit = - std::find(this->Makefiles.begin(), this->Makefiles.end(), mf); - cmLocalGenerator* lg = + std::find_if(this->Makefiles.begin(), this->Makefiles.end(), + [mf](const std::unique_ptr<cmMakefile>& item) { + return item.get() == mf; + }); + auto& lg = this->LocalGenerators[std::distance(this->Makefiles.begin(), mfit)]; for (std::string const& t : targets) { cmGeneratorTarget* gt = lg->FindGeneratorTargetToUse(t); @@ -1309,7 +1317,7 @@ cmExportBuildFileGenerator* cmGlobalGenerator::GetExportedTargetsFile( const std::string& filename) const { auto const it = this->BuildExportSets.find(filename); - return it == this->BuildExportSets.end() ? nullptr : it->second; + return it == this->BuildExportSets.end() ? nullptr : it->second.get(); } void cmGlobalGenerator::AddCMP0042WarnTarget(const std::string& target) @@ -1348,13 +1356,48 @@ void cmGlobalGenerator::ComputeBuildFileGenerators() std::vector<cmExportBuildFileGenerator*> gens = this->Makefiles[i]->GetExportBuildFileGenerators(); for (cmExportBuildFileGenerator* g : gens) { - g->Compute(this->LocalGenerators[i]); + g->Compute(this->LocalGenerators[i].get()); } } } +bool cmGlobalGenerator::UnsupportedVariableIsDefined(const std::string& name, + bool supported) const +{ + if (!supported && this->Makefiles.front()->GetDefinition(name)) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "does not support variable\n" + " " << name << "\n" + "but it has been specified." + ; + /* clang-format on */ + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return true; + } + + return false; +} + bool cmGlobalGenerator::Compute() { + // Make sure unsupported variables are not used. + if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_BUILD_TYPE", + this->SupportsDefaultBuildType())) { + return false; + } + if (this->UnsupportedVariableIsDefined("CMAKE_CROSS_CONFIGS", + this->SupportsCrossConfigs())) { + return false; + } + if (this->UnsupportedVariableIsDefined("CMAKE_DEFAULT_CONFIGS", + this->SupportsDefaultConfigs())) { + return false; + } + // Some generators track files replaced during the Generate. // Start with an empty vector: this->FilesReplacedDuringGenerate.clear(); @@ -1387,7 +1430,7 @@ bool cmGlobalGenerator::Compute() } // Add generator specific helper commands - for (cmLocalGenerator* localGen : this->LocalGenerators) { + for (const auto& localGen : this->LocalGenerators) { localGen->AddHelperCommands(); } @@ -1397,16 +1440,16 @@ bool cmGlobalGenerator::Compute() // on the original cmTarget instance. It accumulates features // across all configurations. Some refactoring is needed to // compute a per-config resulta purely during generation. - for (cmLocalGenerator* localGen : this->LocalGenerators) { + for (const auto& localGen : this->LocalGenerators) { if (!localGen->ComputeTargetCompileFeatures()) { return false; } } - for (cmLocalGenerator* localGen : this->LocalGenerators) { + for (const auto& localGen : this->LocalGenerators) { cmMakefile* mf = localGen->GetMakefile(); - for (cmInstallGenerator* g : mf->GetInstallGenerators()) { - if (!g->Compute(localGen)) { + for (const auto& g : mf->GetInstallGenerators()) { + if (!g->Compute(localGen.get())) { return false; } } @@ -1416,7 +1459,7 @@ bool cmGlobalGenerator::Compute() // Trace the dependencies, after that no custom commands should be added // because their dependencies might not be handled correctly - for (cmLocalGenerator* localGen : this->LocalGenerators) { + for (const auto& localGen : this->LocalGenerators) { localGen->TraceDependencies(); } @@ -1428,7 +1471,7 @@ bool cmGlobalGenerator::Compute() this->ForceLinkerLanguages(); // Compute the manifest of main targets generated. - for (cmLocalGenerator* localGen : this->LocalGenerators) { + for (const auto& localGen : this->LocalGenerators) { localGen->ComputeTargetManifest(); } @@ -1445,7 +1488,7 @@ bool cmGlobalGenerator::Compute() return false; } - for (cmLocalGenerator* localGen : this->LocalGenerators) { + for (const auto& localGen : this->LocalGenerators) { localGen->ComputeHomeRelativeOutputPath(); } @@ -1460,6 +1503,8 @@ void cmGlobalGenerator::Generate() this->ProcessEvaluationFiles(); + this->CMakeInstance->UpdateProgress("Generating", 0.1f); + // Generate project files for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) { this->SetCurrentMakefile(this->LocalGenerators[i]->GetMakefile()); @@ -1471,8 +1516,9 @@ void cmGlobalGenerator::Generate() this->LocalGenerators[i]->GenerateTestFiles(); this->CMakeInstance->UpdateProgress( "Generating", - (static_cast<float>(i) + 1.0f) / - static_cast<float>(this->LocalGenerators.size())); + 0.1f + + 0.9f * (static_cast<float>(i) + 1.0f) / + static_cast<float>(this->LocalGenerators.size())); } this->SetCurrentMakefile(nullptr); @@ -1555,40 +1601,42 @@ bool cmGlobalGenerator::QtAutoGen() bool cmGlobalGenerator::AddAutomaticSources() { - for (cmLocalGenerator* lg : this->LocalGenerators) { + for (const auto& lg : this->LocalGenerators) { lg->CreateEvaluationFileOutputs(); - for (cmGeneratorTarget* gt : lg->GetGeneratorTargets()) { + for (const auto& gt : lg->GetGeneratorTargets()) { if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY || gt->GetType() == cmStateEnums::UTILITY || gt->GetType() == cmStateEnums::GLOBAL_TARGET) { continue; } - lg->AddUnityBuild(gt); - lg->AddPchDependencies(gt); + lg->AddUnityBuild(gt.get()); + lg->AddPchDependencies(gt.get()); } } // The above transformations may have changed the classification of sources. // Clear the source list and classification cache (KindedSources) of all // targets so that it will be recomputed correctly by the generators later // now that the above transformations are done for all targets. - for (cmLocalGenerator* lg : this->LocalGenerators) { - for (cmGeneratorTarget* gt : lg->GetGeneratorTargets()) { + for (const auto& lg : this->LocalGenerators) { + for (const auto& gt : lg->GetGeneratorTargets()) { gt->ClearSourcesCache(); } } return true; } -cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer( +std::unique_ptr<cmLinkLineComputer> cmGlobalGenerator::CreateLinkLineComputer( cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const { - return new cmLinkLineComputer(outputConverter, stateDir); + return cm::make_unique<cmLinkLineComputer>(outputConverter, stateDir); } -cmLinkLineComputer* cmGlobalGenerator::CreateMSVC60LinkLineComputer( +std::unique_ptr<cmLinkLineComputer> +cmGlobalGenerator::CreateMSVC60LinkLineComputer( cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const { - return new cmMSVC60LinkLineComputer(outputConverter, stateDir); + return std::unique_ptr<cmLinkLineComputer>( + cm::make_unique<cmMSVC60LinkLineComputer>(outputConverter, stateDir)); } void cmGlobalGenerator::FinalizeTargetCompileInfo() @@ -1597,7 +1645,7 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo() this->CMakeInstance->GetState()->GetEnabledLanguages(); // Construct per-target generator information. - for (cmMakefile* mf : this->Makefiles) { + for (const auto& mf : this->Makefiles) { const cmStringRange noconfig_compile_definitions = mf->GetCompileDefinitionsEntries(); const cmBacktraceRange noconfig_compile_definitions_bts = @@ -1632,7 +1680,9 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo() for (std::string const& c : configs) { std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(c)); - t->AppendProperty(defPropName, mf->GetProperty(defPropName)); + if (const char* val = mf->GetProperty(defPropName)) { + t->AppendProperty(defPropName, val); + } } } } @@ -1661,8 +1711,7 @@ void cmGlobalGenerator::CreateGeneratorTargets( if (targetTypes == AllTargets) { for (auto& target : mf->GetTargets()) { cmTarget* t = &target.second; - cmGeneratorTarget* gt = new cmGeneratorTarget(t, lg); - lg->AddGeneratorTarget(gt); + lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(t, lg)); } } @@ -1675,31 +1724,28 @@ void cmGlobalGenerator::CreateGeneratorTargets(TargetTypes targetTypes) { std::map<cmTarget*, cmGeneratorTarget*> importedMap; for (unsigned int i = 0; i < this->Makefiles.size(); ++i) { - cmMakefile* mf = this->Makefiles[i]; - for (cmTarget* ownedImpTgt : mf->GetOwnedImportedTargets()) { - cmLocalGenerator* lg = this->LocalGenerators[i]; - cmGeneratorTarget* gt = new cmGeneratorTarget(ownedImpTgt, lg); - lg->AddOwnedImportedGeneratorTarget(gt); - importedMap[ownedImpTgt] = gt; + auto& mf = this->Makefiles[i]; + for (const auto& ownedImpTgt : mf->GetOwnedImportedTargets()) { + cmLocalGenerator* lg = this->LocalGenerators[i].get(); + auto gt = cm::make_unique<cmGeneratorTarget>(ownedImpTgt.get(), lg); + importedMap[ownedImpTgt.get()] = gt.get(); + lg->AddOwnedImportedGeneratorTarget(std::move(gt)); } } // Construct per-target generator information. for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) { - this->CreateGeneratorTargets(targetTypes, this->Makefiles[i], - this->LocalGenerators[i], importedMap); + this->CreateGeneratorTargets(targetTypes, this->Makefiles[i].get(), + this->LocalGenerators[i].get(), importedMap); } } void cmGlobalGenerator::ClearGeneratorMembers() { - cmDeleteAll(this->BuildExportSets); this->BuildExportSets.clear(); - cmDeleteAll(this->Makefiles); this->Makefiles.clear(); - cmDeleteAll(this->LocalGenerators); this->LocalGenerators.clear(); this->AliasTargets.clear(); @@ -1722,12 +1768,12 @@ void cmGlobalGenerator::ComputeTargetObjectDirectory( void cmGlobalGenerator::CheckTargetProperties() { + // check for link libraries and include directories containing "NOTFOUND" + // and for infinite loops std::map<std::string, std::string> notFoundMap; - // std::set<std::string> notFoundMap; - // after it is all done do a ConfigureFinalPass cmState* state = this->GetCMakeInstance()->GetState(); for (unsigned int i = 0; i < this->Makefiles.size(); ++i) { - this->Makefiles[i]->ConfigureFinalPass(); + this->Makefiles[i]->Generate(*this->LocalGenerators[i]); for (auto const& target : this->Makefiles[i]->GetTargets()) { if (target.second.GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; @@ -1771,11 +1817,6 @@ void cmGlobalGenerator::CheckTargetProperties() } } } - this->CMakeInstance->UpdateProgress( - "Configuring", - 0.9f + - 0.1f * (static_cast<float>(i) + 1.0f) / - static_cast<float>(this->Makefiles.size())); } if (!notFoundMap.empty()) { @@ -1872,6 +1913,10 @@ int cmGlobalGenerator::Build( output += "\n"; return 1; } + std::string realConfig = config; + if (realConfig.empty()) { + realConfig = this->GetDefaultBuildConfig(); + } int retVal = 0; cmSystemTools::SetRunCommandHideConsole(true); @@ -1880,7 +1925,7 @@ int cmGlobalGenerator::Build( std::vector<GeneratedMakeCommand> makeCommand = this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, targets, - config, fast, jobs, verbose, nativeOptions); + realConfig, fast, jobs, verbose, nativeOptions); // Workaround to convince some commands to produce output. if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH && @@ -1892,7 +1937,7 @@ int cmGlobalGenerator::Build( if (clean) { std::vector<GeneratedMakeCommand> cleanCommand = this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, - { "clean" }, config, fast, jobs, verbose); + { "clean" }, realConfig, fast, jobs, verbose); output += "\nRun Clean Command:"; output += cleanCommand.front().Printable(); output += "\n"; @@ -1999,10 +2044,10 @@ std::string cmGlobalGenerator::GenerateCMakeBuildCommand( return makeCommand; } -void cmGlobalGenerator::AddMakefile(cmMakefile* mf) +void cmGlobalGenerator::AddMakefile(std::unique_ptr<cmMakefile> mf) { - this->Makefiles.push_back(mf); - this->IndexMakefile(mf); + this->IndexMakefile(mf.get()); + this->Makefiles.push_back(std::move(mf)); // update progress // estimate how many lg there will be @@ -2025,10 +2070,10 @@ void cmGlobalGenerator::AddMakefile(cmMakefile* mf) } int numGen = atoi(numGenC->c_str()); - float prog = 0.9f * static_cast<float>(this->Makefiles.size()) / - static_cast<float>(numGen); - if (prog > 0.9f) { - prog = 0.9f; + float prog = + static_cast<float>(this->Makefiles.size()) / static_cast<float>(numGen); + if (prog > 1.0f) { + prog = 1.0f; } this->CMakeInstance->UpdateProgress("Configuring", prog); } @@ -2045,9 +2090,10 @@ void cmGlobalGenerator::EnableInstallTarget() this->InstallTargetEnabled = true; } -cmLocalGenerator* cmGlobalGenerator::CreateLocalGenerator(cmMakefile* mf) +std::unique_ptr<cmLocalGenerator> cmGlobalGenerator::CreateLocalGenerator( + cmMakefile* mf) { - return new cmLocalGenerator(this, mf); + return cm::make_unique<cmLocalGenerator>(this, mf); } void cmGlobalGenerator::EnableLanguagesFromGenerator(cmGlobalGenerator* gen, @@ -2142,7 +2188,7 @@ int cmGlobalGenerator::GetLinkerPreference(const std::string& lang) const void cmGlobalGenerator::FillProjectMap() { this->ProjectMap.clear(); // make sure we start with a clean map - for (cmLocalGenerator* localGen : this->LocalGenerators) { + for (const auto& localGen : this->LocalGenerators) { // for each local generator add all projects cmStateSnapshot snp = localGen->GetStateSnapshot(); std::string name; @@ -2150,7 +2196,7 @@ void cmGlobalGenerator::FillProjectMap() std::string snpProjName = snp.GetProjectName(); if (name != snpProjName) { name = snpProjName; - this->ProjectMap[name].push_back(localGen); + this->ProjectMap[name].push_back(localGen.get()); } snp = snp.GetBuildsystemDirectoryParent(); } while (snp.IsValid()); @@ -2353,7 +2399,7 @@ void cmGlobalGenerator::CreateDefaultGlobalTargets( void cmGlobalGenerator::AddGlobalTarget_Package( std::vector<GlobalTargetInfo>& targets) { - cmMakefile* mf = this->Makefiles[0]; + auto& mf = this->Makefiles[0]; std::string configFile = cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackConfig.cmake"); if (!cmSystemTools::FileExists(configFile)) { @@ -2402,7 +2448,7 @@ void cmGlobalGenerator::AddGlobalTarget_PackageSource( return; } - cmMakefile* mf = this->Makefiles[0]; + auto& mf = this->Makefiles[0]; std::string configFile = cmStrCat(mf->GetCurrentBinaryDirectory(), "/CPackSourceConfig.cmake"); if (!cmSystemTools::FileExists(configFile)) { @@ -2434,7 +2480,7 @@ void cmGlobalGenerator::AddGlobalTarget_PackageSource( void cmGlobalGenerator::AddGlobalTarget_Test( std::vector<GlobalTargetInfo>& targets) { - cmMakefile* mf = this->Makefiles[0]; + auto& mf = this->Makefiles[0]; if (!mf->IsOn("CMAKE_TESTING_ENABLED")) { return; } @@ -2454,6 +2500,13 @@ void cmGlobalGenerator::AddGlobalTarget_Test( cmCustomCommandLine singleLine; singleLine.push_back(cmSystemTools::GetCTestCommand()); singleLine.push_back("--force-new-ctest-process"); + if (auto testArgs = mf->GetDefinition("CMAKE_CTEST_ARGUMENTS")) { + std::vector<std::string> args; + cmExpandList(testArgs, args); + for (auto const& arg : args) { + singleLine.push_back(arg); + } + } if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') { singleLine.push_back("-C"); singleLine.push_back(cmakeCfgIntDir); @@ -2475,6 +2528,7 @@ void cmGlobalGenerator::AddGlobalTarget_EditCache( } GlobalTargetInfo gti; gti.Name = editCacheTargetName; + gti.PerConfig = false; cmCustomCommandLine singleLine; // Use generator preference for the edit_cache rule if it is defined. @@ -2509,8 +2563,10 @@ void cmGlobalGenerator::AddGlobalTarget_RebuildCache( gti.Name = rebuildCacheTargetName; gti.Message = "Running CMake to regenerate build system..."; gti.UsesTerminal = true; + gti.PerConfig = false; cmCustomCommandLine singleLine; singleLine.push_back(cmSystemTools::GetCMakeCommand()); + singleLine.push_back("--regenerate-during-build"); singleLine.push_back("-S$(CMAKE_SOURCE_DIR)"); singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); gti.CommandLines.push_back(std::move(singleLine)); @@ -2520,7 +2576,7 @@ void cmGlobalGenerator::AddGlobalTarget_RebuildCache( void cmGlobalGenerator::AddGlobalTarget_Install( std::vector<GlobalTargetInfo>& targets) { - cmMakefile* mf = this->Makefiles[0]; + auto& mf = this->Makefiles[0]; const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES"); if (this->InstallTargetEnabled && skipInstallRules) { @@ -2570,7 +2626,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install( singleLine.push_back(cmd); if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') { std::string cfgArg = "-DBUILD_TYPE="; - bool useEPN = this->UseEffectivePlatformName(mf); + bool useEPN = this->UseEffectivePlatformName(mf.get()); if (useEPN) { cfgArg += "$(CONFIGURATION)"; singleLine.push_back(cfgArg); @@ -2653,22 +2709,22 @@ cmTarget cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti, { // Package cmTarget target(gti.Name, cmStateEnums::GLOBAL_TARGET, - cmTarget::VisibilityNormal, mf); + cmTarget::VisibilityNormal, mf, gti.PerConfig); target.SetProperty("EXCLUDE_FROM_ALL", "TRUE"); std::vector<std::string> no_outputs; std::vector<std::string> no_byproducts; std::vector<std::string> no_depends; // Store the custom command in the target. - cmCustomCommand cc(nullptr, no_outputs, no_byproducts, no_depends, - gti.CommandLines, nullptr, gti.WorkingDir.c_str()); + cmCustomCommand cc(no_outputs, no_byproducts, no_depends, gti.CommandLines, + cmListFileBacktrace(), nullptr, gti.WorkingDir.c_str()); cc.SetUsesTerminal(gti.UsesTerminal); target.AddPostBuildCommand(std::move(cc)); if (!gti.Message.empty()) { - target.SetProperty("EchoString", gti.Message.c_str()); + target.SetProperty("EchoString", gti.Message); } for (std::string const& d : gti.Depends) { - target.AddUtility(d); + target.AddUtility(d, false); } // Organize in the "predefined targets" folder: @@ -2737,9 +2793,9 @@ bool cmGlobalGenerator::IsReservedTarget(std::string const& name) } void cmGlobalGenerator::SetExternalMakefileProjectGenerator( - cmExternalMakefileProjectGenerator* extraGenerator) + std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator) { - this->ExtraGenerator.reset(extraGenerator); + this->ExtraGenerator = std::move(extraGenerator); if (this->ExtraGenerator) { this->ExtraGenerator->SetGlobalGenerator(this); } @@ -2765,27 +2821,26 @@ void cmGlobalGenerator::GetFilesReplacedDuringGenerate( std::back_inserter(filenames)); } -void cmGlobalGenerator::GetTargetSets(TargetDependSet& projectTargets, - TargetDependSet& originalTargets, - cmLocalGenerator* root, - GeneratorVector const& generators) +void cmGlobalGenerator::GetTargetSets( + TargetDependSet& projectTargets, TargetDependSet& originalTargets, + cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators) { // loop over all local generators - for (cmLocalGenerator* generator : generators) { + for (auto generator : generators) { // check to make sure generator is not excluded if (this->IsExcluded(root, generator)) { continue; } // loop over all the generator targets in the makefile - for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) { - if (this->IsRootOnlyTarget(target) && + for (const auto& target : generator->GetGeneratorTargets()) { + if (this->IsRootOnlyTarget(target.get()) && target->GetLocalGenerator() != root) { continue; } // put the target in the set of original targets - originalTargets.insert(target); + originalTargets.insert(target.get()); // Get the set of targets that depend on target - this->AddTargetDepends(target, projectTargets); + this->AddTargetDepends(target.get(), projectTargets); } } } @@ -2961,12 +3016,12 @@ void cmGlobalGenerator::WriteSummary() "/CMakeFiles/TargetDirectories.txt"); cmGeneratedFileStream fout(fname); - for (cmLocalGenerator* lg : this->LocalGenerators) { - for (cmGeneratorTarget* tgt : lg->GetGeneratorTargets()) { + for (const auto& lg : this->LocalGenerators) { + for (const auto& tgt : lg->GetGeneratorTargets()) { if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - this->WriteSummary(tgt); + this->WriteSummary(tgt.get()); fout << tgt->GetSupportDirectory() << "\n"; } } @@ -3108,10 +3163,20 @@ cmGlobalGenerator::GetFilenameTargetDepends(cmSourceFile* sf) const return this->FilenameTargetDepends[sf]; } +const std::string& cmGlobalGenerator::GetRealPath(const std::string& dir) +{ + auto i = this->RealPaths.lower_bound(dir); + if (i == this->RealPaths.end() || + this->RealPaths.key_comp()(dir, i->first)) { + i = this->RealPaths.emplace_hint(i, dir, cmSystemTools::GetRealPath(dir)); + } + return i->second; +} + void cmGlobalGenerator::ProcessEvaluationFiles() { std::vector<std::string> generatedFiles; - for (cmLocalGenerator* localGen : this->LocalGenerators) { + for (auto& localGen : this->LocalGenerators) { localGen->ProcessEvaluationFiles(generatedFiles); } } @@ -3127,7 +3192,7 @@ bool cmGlobalGenerator::GenerateCPackPropertiesFile() cmake::InstalledFilesMap const& installedFiles = this->CMakeInstance->GetInstalledFiles(); - cmLocalGenerator* lg = this->LocalGenerators[0]; + const auto& lg = this->LocalGenerators[0]; cmMakefile* mf = lg->GetMakefile(); std::vector<std::string> configs; @@ -3146,8 +3211,8 @@ bool cmGlobalGenerator::GenerateCPackPropertiesFile() for (auto const& i : installedFiles) { cmInstalledFile const& installedFile = i.second; - cmCPackPropertiesGenerator cpackPropertiesGenerator(lg, installedFile, - configs); + cmCPackPropertiesGenerator cpackPropertiesGenerator( + lg.get(), installedFile, configs); cpackPropertiesGenerator.Generate(file, config, configs); } diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index f25ff7b..ba997b2 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -14,9 +14,10 @@ #include <utility> #include <vector> +#include <cmext/algorithm> + #include "cm_codecvt.hxx" -#include "cmAlgorithms.h" #include "cmCustomCommandLines.h" #include "cmDuration.h" #include "cmExportSet.h" @@ -43,6 +44,7 @@ class cmLocalGenerator; class cmMakefile; class cmOutputConverter; class cmSourceFile; +class cmState; class cmStateDirectory; class cmake; @@ -71,7 +73,7 @@ struct GeneratedMakeCommand void Add(std::vector<std::string>::const_iterator start, std::vector<std::string>::const_iterator end) { - cmAppend(PrimaryCommand, start, end); + cm::append(PrimaryCommand, start, end); } std::string Printable() const { return cmJoin(PrimaryCommand, " "); } @@ -90,11 +92,14 @@ struct GeneratedMakeCommand class cmGlobalGenerator { public: + using LocalGeneratorVector = std::vector<std::unique_ptr<cmLocalGenerator>>; + //! Free any memory allocated with the GlobalGenerator cmGlobalGenerator(cmake* cm); virtual ~cmGlobalGenerator(); - virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf); + virtual std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( + cmMakefile* mf); //! Get the name for this generator virtual std::string GetName() const { return "Generic"; } @@ -128,7 +133,14 @@ public: /** Set the generator-specific toolset name. Returns true if toolset is supported and false otherwise. */ - virtual bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf); + virtual bool SetGeneratorToolset(std::string const& ts, bool build, + cmMakefile* mf); + + /** Read any other cache entries needed for cmake --build. */ + virtual bool ReadCacheEntriesForBuild(const cmState& /*state*/) + { + return true; + } /** * Create LocalGenerators and process the CMakeLists files. This does not @@ -157,11 +169,11 @@ public: */ virtual void Generate(); - virtual cmLinkLineComputer* CreateLinkLineComputer( + virtual std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer( cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const; - cmLinkLineComputer* CreateMSVC60LinkLineComputer( + std::unique_ptr<cmLinkLineComputer> CreateMSVC60LinkLineComputer( cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const; @@ -244,11 +256,11 @@ public: cmake* GetCMakeInstance() const { return this->CMakeInstance; } void SetConfiguredFilesPath(cmGlobalGenerator* gen); - const std::vector<cmMakefile*>& GetMakefiles() const + const std::vector<std::unique_ptr<cmMakefile>>& GetMakefiles() const { return this->Makefiles; } - const std::vector<cmLocalGenerator*>& GetLocalGenerators() const + const LocalGeneratorVector& GetLocalGenerators() const { return this->LocalGenerators; } @@ -263,11 +275,11 @@ public: this->CurrentConfigureMakefile = mf; } - void AddMakefile(cmMakefile* mf); + void AddMakefile(std::unique_ptr<cmMakefile> mf); //! Set an generator for an "external makefile based project" void SetExternalMakefileProjectGenerator( - cmExternalMakefileProjectGenerator* extraGenerator); + std::unique_ptr<cmExternalMakefileProjectGenerator> extraGenerator); std::string GetExtraGeneratorName() const; @@ -377,6 +389,9 @@ public: // Lookup edit_cache target command preferred by this generator. virtual std::string GetEditCacheCommand() const { return ""; } + // Default config to use for cmake --build + virtual std::string GetDefaultBuildConfig() const { return "Debug"; } + // Class to track a set of dependencies. using TargetDependSet = cmTargetDependSet; @@ -410,6 +425,8 @@ public: virtual bool IsXcode() const { return false; } + virtual bool IsVisualStudio() const { return false; } + /** Return true if we know the exact location of object files. If false, store the reason in the given string. This is meaningful only after EnableLanguage has been called. */ @@ -431,21 +448,28 @@ public: MacFolder. */ virtual bool ShouldStripResourcePath(cmMakefile*) const; + virtual bool SupportsCustomCommandDepfile() const { return false; } + std::string GetSharedLibFlagsForLanguage(std::string const& lang) const; /** Generate an <output>.rule file path for a given command output. */ virtual std::string GenerateRuleFile(std::string const& output) const; + virtual bool SupportsDefaultBuildType() const { return false; } + virtual bool SupportsCrossConfigs() const { return false; } + virtual bool SupportsDefaultConfigs() const { return false; } + static std::string EscapeJSON(const std::string& s); void ProcessEvaluationFiles(); - std::map<std::string, cmExportBuildFileGenerator*>& GetBuildExportSets() + std::map<std::string, std::unique_ptr<cmExportBuildFileGenerator>>& + GetBuildExportSets() { return this->BuildExportSets; } - void AddBuildExportSet(cmExportBuildFileGenerator*); - void AddBuildExportExportSet(cmExportBuildFileGenerator*); + void AddBuildExportSet(std::unique_ptr<cmExportBuildFileGenerator>); + void AddBuildExportExportSet(std::unique_ptr<cmExportBuildFileGenerator>); bool IsExportedTargetsFile(const std::string& filename) const; bool GenerateImportFile(const std::string& file); cmExportBuildFileGenerator* GetExportedTargetsFile( @@ -475,13 +499,19 @@ public: int RecursionDepth; + virtual void GetQtAutoGenConfigs(std::vector<std::string>& configs) const + { + configs.emplace_back("$<CONFIG>"); + } + + std::string const& GetRealPath(std::string const& dir); + protected: - using GeneratorVector = std::vector<cmLocalGenerator*>; // for a project collect all its targets by following depend // information, and also collect all the targets void GetTargetSets(TargetDependSet& projectTargets, TargetDependSet& originalTargets, cmLocalGenerator* root, - GeneratorVector const&); + std::vector<cmLocalGenerator*>& generators); bool IsRootOnlyTarget(cmGeneratorTarget* target) const; void AddTargetDepends(const cmGeneratorTarget* target, TargetDependSet& projectTargets); @@ -524,6 +554,7 @@ protected: std::vector<std::string> Depends; std::string WorkingDir; bool UsesTerminal = false; + bool PerConfig = true; }; void CreateDefaultGlobalTargets(std::vector<GlobalTargetInfo>& targets); @@ -539,8 +570,8 @@ protected: std::string FindMakeProgramFile; std::string ConfiguredFilesPath; cmake* CMakeInstance; - std::vector<cmMakefile*> Makefiles; - std::vector<cmLocalGenerator*> LocalGenerators; + std::vector<std::unique_ptr<cmMakefile>> Makefiles; + LocalGeneratorVector LocalGenerators; cmMakefile* CurrentConfigureMakefile; // map from project name to vector of local generators in that project std::map<std::string, std::vector<cmLocalGenerator*>> ProjectMap; @@ -549,7 +580,8 @@ protected: std::set<std::string> InstallComponents; // Sets of named target exports cmExportSetMap ExportSets; - std::map<std::string, cmExportBuildFileGenerator*> BuildExportSets; + std::map<std::string, std::unique_ptr<cmExportBuildFileGenerator>> + BuildExportSets; std::map<std::string, cmExportBuildFileGenerator*> BuildExportExportSets; std::map<std::string, std::string> AliasTargets; @@ -646,6 +678,9 @@ private: virtual const char* GetBuildIgnoreErrorsFlag() const { return nullptr; } + bool UnsupportedVariableIsDefined(const std::string& name, + bool supported) const; + // Cache directory content and target files to be built. struct DirectoryContent { @@ -666,6 +701,8 @@ private: mutable std::map<cmSourceFile*, std::set<cmGeneratorTarget const*>> FilenameTargetDepends; + std::map<std::string, std::string> RealPaths; + #if !defined(CMAKE_BOOTSTRAP) // Pool of file locks cmFileLockPool FileLockPool; diff --git a/Source/cmGlobalGeneratorFactory.h b/Source/cmGlobalGeneratorFactory.h index bb5f74c..3709365 100644 --- a/Source/cmGlobalGeneratorFactory.h +++ b/Source/cmGlobalGeneratorFactory.h @@ -8,6 +8,8 @@ #include <string> #include <vector> +#include <cm/memory> + class cmGlobalGenerator; class cmake; struct cmDocumentationEntry; @@ -23,8 +25,8 @@ public: virtual ~cmGlobalGeneratorFactory() = default; /** Create a GlobalGenerator */ - virtual cmGlobalGenerator* CreateGlobalGenerator(const std::string& n, - cmake* cm) const = 0; + virtual std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( + const std::string& n, cmake* cm) const = 0; /** Get the documentation entry for this factory */ virtual void GetDocumentation(cmDocumentationEntry& entry) const = 0; @@ -51,13 +53,13 @@ class cmGlobalGeneratorSimpleFactory : public cmGlobalGeneratorFactory { public: /** Create a GlobalGenerator */ - cmGlobalGenerator* CreateGlobalGenerator(const std::string& name, - cmake* cm) const override + std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( + const std::string& name, cmake* cm) const override { if (name != T::GetActualName()) { - return nullptr; + return std::unique_ptr<cmGlobalGenerator>(); } - return new T(cm); + return std::unique_ptr<cmGlobalGenerator>(cm::make_unique<T>(cm)); } /** Get the documentation entry for this factory */ diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index 5a708ab..9754fd5 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -8,6 +8,9 @@ #include <ostream> #include <utility> +#include <cm/memory> +#include <cm/string> + #include "cmAlgorithms.h" #include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" @@ -40,10 +43,11 @@ cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm) cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator() = default; -cmLocalGenerator* cmGlobalGhsMultiGenerator::CreateLocalGenerator( - cmMakefile* mf) +std::unique_ptr<cmLocalGenerator> +cmGlobalGhsMultiGenerator::CreateLocalGenerator(cmMakefile* mf) { - return new cmLocalGhsMultiGenerator(this, mf); + return std::unique_ptr<cmLocalGenerator>( + cm::make_unique<cmLocalGhsMultiGenerator>(this, mf)); } void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry& entry) @@ -64,8 +68,11 @@ void cmGlobalGhsMultiGenerator::ComputeTargetObjectDirectory( } bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts, - cmMakefile* mf) + bool build, cmMakefile* mf) { + if (build) { + return true; + } std::string tsp; /* toolset path */ this->GetToolset(mf, tsp, ts); @@ -84,7 +91,7 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts, /* store the full toolset for later use * -- already done if -T<toolset> was specified */ - mf->AddCacheDefinition("CMAKE_GENERATOR_TOOLSET", tsp.c_str(), + mf->AddCacheDefinition("CMAKE_GENERATOR_TOOLSET", tsp, "Location of generator toolset.", cmStateEnums::INTERNAL); } @@ -106,8 +113,8 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts, } /* store the toolset that is being used for this build */ - mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild.c_str(), - "build program to use", cmStateEnums::INTERNAL, true); + mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild, "build program to use", + cmStateEnums::INTERNAL, true); mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsp); @@ -126,7 +133,7 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p, /* store the platform name for later use * -- already done if -A<arch> was specified */ - mf->AddCacheDefinition("CMAKE_GENERATOR_PLATFORM", arch.c_str(), + mf->AddCacheDefinition("CMAKE_GENERATOR_PLATFORM", arch, "Name of generator platform.", cmStateEnums::INTERNAL); } else { @@ -160,7 +167,7 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p, if (cmIsOff(bspName) && platform.find("integrity") != std::string::npos) { bspName = "sim" + arch; /* write back the calculate name for next time */ - mf->AddCacheDefinition("GHS_BSP_NAME", bspName.c_str(), + mf->AddCacheDefinition("GHS_BSP_NAME", bspName, "Name of GHS target platform.", cmStateEnums::STRING, true); std::string m = cmStrCat( @@ -645,21 +652,16 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives( char const* const customization = this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION"); if (nullptr != customization && strlen(customization) > 0) { - fout << "customization=" << this->TrimQuotes(customization) << std::endl; + fout << "customization=" + << cmGlobalGhsMultiGenerator::TrimQuotes(customization) << std::endl; this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION"); } } -std::string cmGlobalGhsMultiGenerator::TrimQuotes(std::string const& str) +std::string cmGlobalGhsMultiGenerator::TrimQuotes(std::string str) { - std::string result; - result.reserve(str.size()); - for (const char* ch = str.c_str(); *ch != '\0'; ++ch) { - if (*ch != '"') { - result += *ch; - } - } - return result; + cm::erase(str, '"'); + return str; } bool cmGlobalGhsMultiGenerator::TargetCompare::operator()( diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h index ccfe073..12ca8b6 100644 --- a/Source/cmGlobalGhsMultiGenerator.h +++ b/Source/cmGlobalGhsMultiGenerator.h @@ -4,6 +4,7 @@ #define cmGhsMultiGenerator_h #include <iosfwd> +#include <memory> #include <set> #include <string> #include <utility> @@ -28,13 +29,15 @@ public: cmGlobalGhsMultiGenerator(cmake* cm); ~cmGlobalGhsMultiGenerator() override; - static cmGlobalGeneratorFactory* NewFactory() + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() { - return new cmGlobalGeneratorSimpleFactory<cmGlobalGhsMultiGenerator>(); + return std::unique_ptr<cmGlobalGeneratorFactory>( + new cmGlobalGeneratorSimpleFactory<cmGlobalGhsMultiGenerator>()); } //! create the correct local generator - cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override; + std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( + cmMakefile* mf) override; /// @return the name of this generator. static std::string GetActualName() { return "Green Hills MULTI"; } @@ -58,7 +61,8 @@ public: static bool SupportsPlatform() { return true; } // Toolset / Platform Support - bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override; + bool SetGeneratorToolset(std::string const& ts, bool build, + cmMakefile* mf) override; bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override; /** @@ -107,7 +111,7 @@ private: std::vector<cmLocalGenerator*>& generators, std::string& all_target); - std::string TrimQuotes(std::string const& str); + static std::string TrimQuotes(std::string str); std::string OsDir; static const char* DEFAULT_BUILD_PROGRAM; diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx index ff54288..fc3123a 100644 --- a/Source/cmGlobalJOMMakefileGenerator.cxx +++ b/Source/cmGlobalJOMMakefileGenerator.cxx @@ -66,7 +66,7 @@ cmGlobalJOMMakefileGenerator::GenerateBuildCommand( // Since we have full control over the invocation of JOM, let us // make it quiet. jomMakeOptions.push_back(this->MakeSilentFlag); - cmAppend(jomMakeOptions, makeOptions); + cm::append(jomMakeOptions, makeOptions); // JOM does parallel builds by default, the -j is only needed if a specific // number is given diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h index fc39ddf..9f1ec8b 100644 --- a/Source/cmGlobalJOMMakefileGenerator.h +++ b/Source/cmGlobalJOMMakefileGenerator.h @@ -4,6 +4,7 @@ #define cmGlobalJOMMakefileGenerator_h #include <iosfwd> +#include <memory> #include "cmGlobalUnixMakefileGenerator3.h" @@ -16,9 +17,10 @@ class cmGlobalJOMMakefileGenerator : public cmGlobalUnixMakefileGenerator3 { public: cmGlobalJOMMakefileGenerator(cmake* cm); - static cmGlobalGeneratorFactory* NewFactory() + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() { - return new cmGlobalGeneratorSimpleFactory<cmGlobalJOMMakefileGenerator>(); + return std::unique_ptr<cmGlobalGeneratorFactory>( + new cmGlobalGeneratorSimpleFactory<cmGlobalJOMMakefileGenerator>()); } //! Get the name for the generator. std::string GetName() const override diff --git a/Source/cmGlobalMSYSMakefileGenerator.h b/Source/cmGlobalMSYSMakefileGenerator.h index d6e4847..b2de4ff 100644 --- a/Source/cmGlobalMSYSMakefileGenerator.h +++ b/Source/cmGlobalMSYSMakefileGenerator.h @@ -3,6 +3,8 @@ #ifndef cmGlobalMSYSMakefileGenerator_h #define cmGlobalMSYSMakefileGenerator_h +#include <memory> + #include "cmGlobalUnixMakefileGenerator3.h" /** \class cmGlobalMSYSMakefileGenerator @@ -14,9 +16,10 @@ class cmGlobalMSYSMakefileGenerator : public cmGlobalUnixMakefileGenerator3 { public: cmGlobalMSYSMakefileGenerator(cmake* cm); - static cmGlobalGeneratorFactory* NewFactory() + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() { - return new cmGlobalGeneratorSimpleFactory<cmGlobalMSYSMakefileGenerator>(); + return std::unique_ptr<cmGlobalGeneratorFactory>( + new cmGlobalGeneratorSimpleFactory<cmGlobalMSYSMakefileGenerator>()); } //! Get the name for the generator. diff --git a/Source/cmGlobalMinGWMakefileGenerator.h b/Source/cmGlobalMinGWMakefileGenerator.h index 15297e3..a9f92a1 100644 --- a/Source/cmGlobalMinGWMakefileGenerator.h +++ b/Source/cmGlobalMinGWMakefileGenerator.h @@ -3,6 +3,8 @@ #ifndef cmGlobalMinGWMakefileGenerator_h #define cmGlobalMinGWMakefileGenerator_h +#include <memory> + #include "cmGlobalUnixMakefileGenerator3.h" /** \class cmGlobalMinGWMakefileGenerator @@ -14,10 +16,10 @@ class cmGlobalMinGWMakefileGenerator : public cmGlobalUnixMakefileGenerator3 { public: cmGlobalMinGWMakefileGenerator(cmake* cm); - static cmGlobalGeneratorFactory* NewFactory() + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() { - return new cmGlobalGeneratorSimpleFactory< - cmGlobalMinGWMakefileGenerator>(); + return std::unique_ptr<cmGlobalGeneratorFactory>( + new cmGlobalGeneratorSimpleFactory<cmGlobalMinGWMakefileGenerator>()); } //! Get the name for the generator. virtual std::string GetName() const diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx index 2273c00..c4bec23 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.cxx +++ b/Source/cmGlobalNMakeMakefileGenerator.cxx @@ -66,7 +66,7 @@ cmGlobalNMakeMakefileGenerator::GenerateBuildCommand( // Since we have full control over the invocation of nmake, let us // make it quiet. nmakeMakeOptions.push_back(this->MakeSilentFlag); - cmAppend(nmakeMakeOptions, makeOptions); + cm::append(nmakeMakeOptions, makeOptions); return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( makeProgram, projectName, projectDir, targetNames, config, fast, diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h index 4586b77..fdf6006 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.h +++ b/Source/cmGlobalNMakeMakefileGenerator.h @@ -4,6 +4,7 @@ #define cmGlobalNMakeMakefileGenerator_h #include <iosfwd> +#include <memory> #include "cmGlobalUnixMakefileGenerator3.h" @@ -16,10 +17,10 @@ class cmGlobalNMakeMakefileGenerator : public cmGlobalUnixMakefileGenerator3 { public: cmGlobalNMakeMakefileGenerator(cmake* cm); - static cmGlobalGeneratorFactory* NewFactory() + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() { - return new cmGlobalGeneratorSimpleFactory< - cmGlobalNMakeMakefileGenerator>(); + return std::unique_ptr<cmGlobalGeneratorFactory>( + new cmGlobalGeneratorSimpleFactory<cmGlobalNMakeMakefileGenerator>()); } //! Get the name for the generator. std::string GetName() const override diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index da21d6c..d58113c 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -9,6 +9,8 @@ #include <sstream> #include <cm/memory> +#include <cmext/algorithm> +#include <cmext/memory> #include "cmsys/FStream.hxx" @@ -23,6 +25,7 @@ #include "cmGeneratorExpressionEvaluationFile.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmLinkLineComputer.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" @@ -42,10 +45,9 @@ #include "cmVersion.h" #include "cmake.h" -class cmLinkLineComputer; - const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja"; -const char* cmGlobalNinjaGenerator::NINJA_RULES_FILE = "rules.ninja"; +const char* cmGlobalNinjaGenerator::NINJA_RULES_FILE = + "CMakeFiles/rules.ninja"; const char* cmGlobalNinjaGenerator::INDENT = " "; #ifdef _WIN32 std::string const cmGlobalNinjaGenerator::SHELL_NOOP = "cd ."; @@ -83,13 +85,15 @@ void cmGlobalNinjaGenerator::WriteComment(std::ostream& os, os << "# " << comment.substr(lpos) << "\n\n"; } -cmLinkLineComputer* cmGlobalNinjaGenerator::CreateLinkLineComputer( +std::unique_ptr<cmLinkLineComputer> +cmGlobalNinjaGenerator::CreateLinkLineComputer( cmOutputConverter* outputConverter, cmStateDirectory const& /* stateDir */) const { - return new cmNinjaLinkLineComputer( - outputConverter, - this->LocalGenerators[0]->GetStateSnapshot().GetDirectory(), this); + return std::unique_ptr<cmLinkLineComputer>( + cm::make_unique<cmNinjaLinkLineComputer>( + outputConverter, + this->LocalGenerators[0]->GetStateSnapshot().GetDirectory(), this)); } std::string cmGlobalNinjaGenerator::EncodeRuleName(std::string const& name) @@ -114,6 +118,11 @@ std::string cmGlobalNinjaGenerator::EncodeLiteral(const std::string& lit) std::string result = lit; cmSystemTools::ReplaceString(result, "$", "$$"); cmSystemTools::ReplaceString(result, "\n", "$\n"); + if (this->IsMultiConfig()) { + cmSystemTools::ReplaceString(result, + cmStrCat('$', this->GetCMakeCFGIntDir()), + this->GetCMakeCFGIntDir()); + } return result; } @@ -139,15 +148,15 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, { // Make sure there is a rule. if (build.Rule.empty()) { - cmSystemTools::Error("No rule for WriteBuild! called with comment: " + - build.Comment); + cmSystemTools::Error(cmStrCat( + "No rule for WriteBuild! called with comment: ", build.Comment)); return; } // Make sure there is at least one output file. if (build.Outputs.empty()) { - cmSystemTools::Error( - "No output files for WriteBuild! called with comment: " + build.Comment); + cmSystemTools::Error(cmStrCat( + "No output files for WriteBuild! called with comment: ", build.Comment)); return; } @@ -158,7 +167,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, { // Write explicit outputs for (std::string const& output : build.Outputs) { - buildStr += " " + EncodePath(output); + buildStr += cmStrCat(' ', EncodePath(output)); if (this->ComputingUnknownDependencies) { this->CombinedBuildOutputs.insert(output); } @@ -167,14 +176,13 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, if (!build.ImplicitOuts.empty()) { buildStr += " |"; for (std::string const& implicitOut : build.ImplicitOuts) { - buildStr += " " + EncodePath(implicitOut); + buildStr += cmStrCat(' ', EncodePath(implicitOut)); } } - buildStr += ":"; + buildStr += ':'; // Write the rule. - buildStr += " "; - buildStr += build.Rule; + buildStr += cmStrCat(' ', build.Rule); } std::string arguments; @@ -183,14 +191,14 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, // Write explicit dependencies. for (std::string const& explicitDep : build.ExplicitDeps) { - arguments += " " + EncodePath(explicitDep); + arguments += cmStrCat(' ', EncodePath(explicitDep)); } // Write implicit dependencies. if (!build.ImplicitDeps.empty()) { arguments += " |"; for (std::string const& implicitDep : build.ImplicitDeps) { - arguments += " " + EncodePath(implicitDep); + arguments += cmStrCat(' ', EncodePath(implicitDep)); } } @@ -198,11 +206,11 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, if (!build.OrderOnlyDeps.empty()) { arguments += " ||"; for (std::string const& orderOnlyDep : build.OrderOnlyDeps) { - arguments += " " + EncodePath(orderOnlyDep); + arguments += cmStrCat(' ', EncodePath(orderOnlyDep)); } } - arguments += "\n"; + arguments += '\n'; } // Write the variables bound to this build statement. @@ -248,8 +256,8 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( const std::string& command, const std::string& description, const std::string& comment, const std::string& depfile, const std::string& job_pool, bool uses_terminal, bool restat, - const cmNinjaDeps& outputs, const cmNinjaDeps& explicitDeps, - const cmNinjaDeps& orderOnlyDeps) + const cmNinjaDeps& outputs, const std::string& config, + const cmNinjaDeps& explicitDeps, const cmNinjaDeps& orderOnlyDeps) { this->AddCustomCommandRule(); @@ -282,7 +290,11 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( if (!depfile.empty()) { vars["depfile"] = depfile; } - this->WriteBuild(*this->BuildFileStream, build); + if (config.empty()) { + this->WriteBuild(*this->GetCommonFileStream(), build); + } else { + this->WriteBuild(*this->GetImplFileStream(config), build); + } } if (this->ComputingUnknownDependencies) { @@ -297,21 +309,22 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( void cmGlobalNinjaGenerator::AddMacOSXContentRule() { cmNinjaRule rule("COPY_OSX_CONTENT"); - rule.Command = CMakeCmd() + " -E copy $in $out"; + rule.Command = cmStrCat(CMakeCmd(), " -E copy $in $out"); rule.Description = "Copying OS X Content $out"; rule.Comment = "Rule for copying OS X bundle content file."; this->AddRule(rule); } void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(std::string input, - std::string output) + std::string output, + const std::string& config) { this->AddMacOSXContentRule(); { cmNinjaBuild build("COPY_OSX_CONTENT"); build.Outputs.push_back(std::move(output)); build.ExplicitDeps.push_back(std::move(input)); - this->WriteBuild(*this->BuildFileStream, build); + this->WriteBuild(*this->GetImplFileStream(config), build); } } @@ -321,23 +334,24 @@ void cmGlobalNinjaGenerator::WriteRule(std::ostream& os, // -- Parameter checks // Make sure the rule has a name. if (rule.Name.empty()) { - cmSystemTools::Error("No name given for WriteRule! called with comment: " + - rule.Comment); + cmSystemTools::Error(cmStrCat( + "No name given for WriteRule! called with comment: ", rule.Comment)); return; } // Make sure a command is given. if (rule.Command.empty()) { - cmSystemTools::Error( - "No command given for WriteRule! called with comment: " + rule.Comment); + cmSystemTools::Error(cmStrCat( + "No command given for WriteRule! called with comment: ", rule.Comment)); return; } // Make sure response file content is given if (!rule.RspFile.empty() && rule.RspContent.empty()) { - cmSystemTools::Error("rspfile but no rspfile_content given for WriteRule! " - "called with comment: " + - rule.Comment); + cmSystemTools::Error( + cmStrCat("rspfile but no rspfile_content given for WriteRule! " + "called with comment: ", + rule.Comment)); return; } @@ -379,9 +393,9 @@ void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os, { // Make sure we have a name. if (name.empty()) { - cmSystemTools::Error("No name given for WriteVariable! called " - "with comment: " + - comment); + cmSystemTools::Error(cmStrCat("No name given for WriteVariable! called " + "with comment: ", + comment)); return; } @@ -429,9 +443,11 @@ cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm) // Virtual public methods. -cmLocalGenerator* cmGlobalNinjaGenerator::CreateLocalGenerator(cmMakefile* mf) +std::unique_ptr<cmLocalGenerator> cmGlobalNinjaGenerator::CreateLocalGenerator( + cmMakefile* mf) { - return new cmLocalNinjaGenerator(this, mf); + return std::unique_ptr<cmLocalGenerator>( + cm::make_unique<cmLocalNinjaGenerator>(this, mf)); } codecvt::Encoding cmGlobalNinjaGenerator::GetMakefileEncoding() const @@ -470,14 +486,19 @@ void cmGlobalNinjaGenerator::Generate() msg.str()); return; } - if (!this->OpenBuildFileStream()) { + if (!this->InspectConfigTypeVariables()) { + return; + } + if (!this->OpenBuildFileStreams()) { return; } if (!this->OpenRulesFileStream()) { return; } - this->TargetDependsClosures.clear(); + for (auto& it : this->Configs) { + it.second.TargetDependsClosures.clear(); + } this->InitOutputPathPrefix(); this->TargetAll = this->NinjaOutputPath("all"); @@ -493,19 +514,101 @@ void cmGlobalNinjaGenerator::Generate() this->cmGlobalGenerator::Generate(); this->WriteAssumedSourceDependencies(); - this->WriteTargetAliases(*this->BuildFileStream); - this->WriteFolderTargets(*this->BuildFileStream); - this->WriteUnknownExplicitDependencies(*this->BuildFileStream); - this->WriteBuiltinTargets(*this->BuildFileStream); + this->WriteTargetAliases(*this->GetCommonFileStream()); + this->WriteFolderTargets(*this->GetCommonFileStream()); + this->WriteUnknownExplicitDependencies(*this->GetCommonFileStream()); + this->WriteBuiltinTargets(*this->GetCommonFileStream()); if (cmSystemTools::GetErrorOccuredFlag()) { this->RulesFileStream->setstate(std::ios::failbit); - this->BuildFileStream->setstate(std::ios::failbit); + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + this->GetImplFileStream(config)->setstate(std::ios::failbit); + this->GetConfigFileStream(config)->setstate(std::ios::failbit); + } + this->GetCommonFileStream()->setstate(std::ios::failbit); } this->CloseCompileCommandsStream(); this->CloseRulesFileStream(); - this->CloseBuildFileStream(); + this->CloseBuildFileStreams(); + +#ifdef _WIN32 + // The ninja tools will not be able to update metadata on Windows + // when we are re-generating inside an existing 'ninja' invocation + // because the outer tool has the files open for write. + if (!this->GetCMakeInstance()->GetRegenerateDuringBuild()) +#endif + { + this->CleanMetaData(); + } +} + +void cmGlobalNinjaGenerator::CleanMetaData() +{ + auto run_ninja_tool = [this](std::vector<char const*> const& args) { + std::vector<std::string> command; + command.push_back(this->NinjaCommand); + command.emplace_back("-C"); + command.emplace_back(this->GetCMakeInstance()->GetHomeOutputDirectory()); + command.emplace_back("-t"); + for (auto const& arg : args) { + command.emplace_back(arg); + } + std::string error; + if (!cmSystemTools::RunSingleCommand(command, nullptr, &error, nullptr, + nullptr, + cmSystemTools::OUTPUT_NONE)) { + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("Running\n '", + cmJoin(command, "' '"), + "'\n" + "failed with:\n ", + error)); + cmSystemTools::SetFatalErrorOccured(); + } + }; + + // Can the tools below expect 'build.ninja' to be loadable? + bool const expectBuildManifest = + !this->IsMultiConfig() && this->OutputPathPrefix.empty(); + + // Skip some ninja tools if they need 'build.ninja' but it is missing. + bool const missingBuildManifest = expectBuildManifest && + (this->NinjaSupportsCleanDeadTool || + this->NinjaSupportsUnconditionalRecompactTool) && + !cmSystemTools::FileExists("build.ninja"); + + // The `cleandead` tool needs to know about all outputs in the build we just + // wrote out. Ninja-Multi doesn't have a single `build.ninja` we can use that + // is the union of all generated configurations, so we can't run it reliably + // in that case. + if (this->NinjaSupportsCleanDeadTool && expectBuildManifest && + !missingBuildManifest) { + run_ninja_tool({ "cleandead" }); + } + // The `recompact` tool loads the manifest. As above, we don't have a single + // `build.ninja` to load for this in Ninja-Multi. This may be relaxed in the + // future pending further investigation into how Ninja works upstream + // (ninja#1721). + if (this->NinjaSupportsUnconditionalRecompactTool && expectBuildManifest && + !missingBuildManifest) { + run_ninja_tool({ "recompact" }); + } + if (this->NinjaSupportsRestatTool && this->OutputPathPrefix.empty()) { + // XXX(ninja): We only list `build.ninja` entry files here because CMake + // *always* rewrites these files on a reconfigure. If CMake ever gets + // smarter about this, all CMake-time created/edited files listed as + // outputs for the reconfigure build statement will need to be listed here. + cmNinjaDeps outputs; + this->AddRebuildManifestOutputs(outputs); + std::vector<const char*> args; + args.reserve(outputs.size() + 1); + args.push_back("restat"); + for (auto const& output : outputs) { + args.push_back(output.c_str()); + } + run_ninja_tool(args); + } } bool cmGlobalNinjaGenerator::FindMakeProgram(cmMakefile* mf) @@ -524,10 +627,10 @@ bool cmGlobalNinjaGenerator::FindMakeProgram(cmMakefile* mf) nullptr, cmSystemTools::OUTPUT_NONE)) { mf->IssueMessage(MessageType::FATAL_ERROR, - "Running\n '" + cmJoin(command, "' '") + - "'\n" - "failed with:\n " + - error); + cmStrCat("Running\n '", cmJoin(command, "' '"), + "'\n" + "failed with:\n ", + error)); cmSystemTools::SetFatalErrorOccured(); return false; } @@ -569,6 +672,16 @@ void cmGlobalNinjaGenerator::CheckNinjaFeatures() } } } + this->NinjaSupportsCleanDeadTool = !cmSystemTools::VersionCompare( + cmSystemTools::OP_LESS, this->NinjaVersion.c_str(), + RequiredNinjaVersionForCleanDeadTool().c_str()); + this->NinjaSupportsUnconditionalRecompactTool = + !cmSystemTools::VersionCompare( + cmSystemTools::OP_LESS, this->NinjaVersion.c_str(), + RequiredNinjaVersionForUnconditionalRecompactTool().c_str()); + this->NinjaSupportsRestatTool = !cmSystemTools::VersionCompare( + cmSystemTools::OP_LESS, this->NinjaVersion.c_str(), + RequiredNinjaVersionForRestatTool().c_str()); } bool cmGlobalNinjaGenerator::CheckLanguages( @@ -577,6 +690,17 @@ bool cmGlobalNinjaGenerator::CheckLanguages( if (cmContains(languages, "Fortran")) { return this->CheckFortran(mf); } + if (cmContains(languages, "Swift")) { + const std::string architectures = + mf->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES"); + if (architectures.find_first_of(';') != std::string::npos) { + mf->IssueMessage(MessageType::FATAL_ERROR, + "multiple values for CMAKE_OSX_ARCHITECTURES not " + "supported with Swift"); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + } return true; } @@ -590,7 +714,7 @@ bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const /* clang-format off */ e << "The Ninja generator does not support Fortran using Ninja version\n" - " " + this->NinjaVersion + "\n" + " " << this->NinjaVersion << "\n" "due to lack of required features. " "Kitware has implemented the required features and they have been " "merged to upstream ninja for inclusion in Ninja 1.10 and higher. " @@ -609,6 +733,17 @@ bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const void cmGlobalNinjaGenerator::EnableLanguage( std::vector<std::string> const& langs, cmMakefile* mf, bool optional) { + if (this->IsMultiConfig()) { + if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) { + mf->AddCacheDefinition( + "CMAKE_CONFIGURATION_TYPES", "Debug;Release;RelWithDebInfo", + "Semicolon separated list of supported configuration types, only " + "supports Debug, Release, MinSizeRel, and RelWithDebInfo, anything " + "else will be ignored", + cmStateEnums::STRING); + } + } + this->cmGlobalGenerator::EnableLanguage(langs, mf, optional); for (std::string const& l : langs) { if (l == "NONE") { @@ -650,7 +785,7 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand> cmGlobalNinjaGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& /*projectName*/, const std::string& /*projectDir*/, - std::vector<std::string> const& targetNames, const std::string& /*config*/, + std::vector<std::string> const& targetNames, const std::string& config, bool /*fast*/, int jobs, bool verbose, std::vector<std::string> const& makeOptions) { @@ -666,6 +801,8 @@ cmGlobalNinjaGenerator::GenerateBuildCommand( makeCommand.Add("-j", std::to_string(jobs)); } + this->AppendNinjaFileArgument(makeCommand, config); + makeCommand.Add(makeOptions.begin(), makeOptions.end()); for (const auto& tname : targetNames) { if (!tname.empty()) { @@ -707,44 +844,76 @@ void cmGlobalNinjaGenerator::ComputeTargetObjectDirectory( cmGeneratorTarget* gt) const { // Compute full path to object file directory for this target. - std::string dir = - cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), '/', - gt->LocalGenerator->GetTargetDirectory(gt), '/'); + std::string dir = cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), + '/', gt->LocalGenerator->GetTargetDirectory(gt), + '/', this->GetCMakeCFGIntDir(), '/'); gt->ObjectDirectory = dir; } // Private methods -bool cmGlobalNinjaGenerator::OpenBuildFileStream() +bool cmGlobalNinjaGenerator::OpenBuildFileStreams() { - // Compute Ninja's build file path. - std::string buildFilePath = - cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), '/', - cmGlobalNinjaGenerator::NINJA_BUILD_FILE); + if (!this->OpenFileStream(this->BuildFileStream, + cmGlobalNinjaGenerator::NINJA_BUILD_FILE)) { + return false; + } + + // Write a comment about this file. + *this->BuildFileStream + << "# This file contains all the build statements describing the\n" + << "# compilation DAG.\n\n"; + + return true; +} +bool cmGlobalNinjaGenerator::OpenFileStream( + std::unique_ptr<cmGeneratedFileStream>& stream, const std::string& name) +{ // Get a stream where to generate things. - if (!this->BuildFileStream) { - this->BuildFileStream = cm::make_unique<cmGeneratedFileStream>( - buildFilePath, false, this->GetMakefileEncoding()); - if (!(*this->BuildFileStream)) { + if (!stream) { + // Compute Ninja's build file path. + std::string path = + cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), '/', name); + stream = cm::make_unique<cmGeneratedFileStream>( + path, false, this->GetMakefileEncoding()); + if (!(*stream)) { // An error message is generated by the constructor if it cannot // open the file. return false; } + + // Write the do not edit header. + this->WriteDisclaimer(*stream); } - // Write the do not edit header. - this->WriteDisclaimer(*this->BuildFileStream); + return true; +} - // Write a comment about this file. - *this->BuildFileStream - << "# This file contains all the build statements describing the\n" - << "# compilation DAG.\n\n"; +cm::optional<std::set<std::string>> cmGlobalNinjaGenerator::ListSubsetWithAll( + const std::set<std::string>& all, const std::set<std::string>& defaults, + const std::vector<std::string>& items) +{ + std::set<std::string> result; - return true; + for (auto const& item : items) { + if (item == "all") { + if (items.size() == 1) { + result = defaults; + } else { + return cm::nullopt; + } + } else if (all.count(item)) { + result.insert(item); + } else { + return cm::nullopt; + } + } + + return cm::make_optional(result); } -void cmGlobalNinjaGenerator::CloseBuildFileStream() +void cmGlobalNinjaGenerator::CloseBuildFileStreams() { if (this->BuildFileStream) { this->BuildFileStream.reset(); @@ -755,25 +924,11 @@ void cmGlobalNinjaGenerator::CloseBuildFileStream() bool cmGlobalNinjaGenerator::OpenRulesFileStream() { - // Compute Ninja's build file path. - std::string rulesFilePath = - cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), '/', - cmGlobalNinjaGenerator::NINJA_RULES_FILE); - - // Get a stream where to generate things. - if (!this->RulesFileStream) { - this->RulesFileStream = cm::make_unique<cmGeneratedFileStream>( - rulesFilePath, false, this->GetMakefileEncoding()); - if (!(*this->RulesFileStream)) { - // An error message is generated by the constructor if it cannot - // open the file. - return false; - } + if (!this->OpenFileStream(this->RulesFileStream, + cmGlobalNinjaGenerator::NINJA_RULES_FILE)) { + return false; } - // Write the do not edit header. - this->WriteDisclaimer(*this->RulesFileStream); - // Write comment about this file. /* clang-format off */ *this->RulesFileStream @@ -819,10 +974,10 @@ std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath( return f->second; } - cmLocalNinjaGenerator* ng = - static_cast<cmLocalNinjaGenerator*>(this->LocalGenerators[0]); - std::string const& bin_dir = ng->GetState()->GetBinaryDirectory(); - std::string convPath = ng->MaybeConvertToRelativePath(bin_dir, path); + const auto& ng = + cm::static_reference_cast<cmLocalNinjaGenerator>(this->LocalGenerators[0]); + std::string const& bin_dir = ng.GetState()->GetBinaryDirectory(); + std::string convPath = ng.MaybeConvertToRelativePath(bin_dir, path); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); @@ -831,9 +986,10 @@ std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath( .first->second; } -void cmGlobalNinjaGenerator::AddAdditionalCleanFile(std::string fileName) +void cmGlobalNinjaGenerator::AddAdditionalCleanFile(std::string fileName, + const std::string& config) { - this->AdditionalCleanFiles.emplace(std::move(fileName)); + this->Configs[config].AdditionalCleanFiles.emplace(std::move(fileName)); } void cmGlobalNinjaGenerator::AddCXXCompileCommand( @@ -843,7 +999,8 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand( std::string buildFileDir = this->GetCMakeInstance()->GetHomeOutputDirectory(); if (!this->CompileCommandsStream) { - std::string buildFilePath = buildFileDir + "/compile_commands.json"; + std::string buildFilePath = + cmStrCat(buildFileDir, "/compile_commands.json"); if (this->ComputingUnknownDependencies) { this->CombinedBuildOutputs.insert( this->NinjaOutputPath("compile_commands.json")); @@ -901,23 +1058,22 @@ void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies() "Assume dependencies for generated source file.", /*depfile*/ "", /*job_pool*/ "", /*uses_terminal*/ false, - /*restat*/ true, cmNinjaDeps(1, asd.first), + /*restat*/ true, cmNinjaDeps(1, asd.first), "", cmNinjaDeps(), orderOnlyDeps); } } -std::string OrderDependsTargetForTarget(cmGeneratorTarget const* target) +std::string cmGlobalNinjaGenerator::OrderDependsTargetForTarget( + cmGeneratorTarget const* target, const std::string& config) { - return "cmake_object_order_depends_target_" + target->GetName(); + return cmStrCat("cmake_object_order_depends_target_", target->GetName(), '_', + config); } void cmGlobalNinjaGenerator::AppendTargetOutputs( cmGeneratorTarget const* target, cmNinjaDeps& outputs, - cmNinjaTargetDepends depends) + const std::string& config, cmNinjaTargetDepends depends) { - std::string configName = - target->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"); - // for frameworks, we want the real name, not smple name // frameworks always appear versioned, and the build.ninja // will always attempt to manage symbolic links instead @@ -929,19 +1085,19 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( case cmStateEnums::STATIC_LIBRARY: case cmStateEnums::MODULE_LIBRARY: { if (depends == DependOnTargetOrdering) { - outputs.push_back(OrderDependsTargetForTarget(target)); + outputs.push_back(OrderDependsTargetForTarget(target, config)); break; } } // FALLTHROUGH case cmStateEnums::EXECUTABLE: { outputs.push_back(this->ConvertToNinjaPath(target->GetFullPath( - configName, cmStateEnums::RuntimeBinaryArtifact, realname))); + config, cmStateEnums::RuntimeBinaryArtifact, realname))); break; } case cmStateEnums::OBJECT_LIBRARY: { if (depends == DependOnTargetOrdering) { - outputs.push_back(OrderDependsTargetForTarget(target)); + outputs.push_back(OrderDependsTargetForTarget(target, config)); break; } } @@ -949,9 +1105,13 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( case cmStateEnums::GLOBAL_TARGET: case cmStateEnums::UTILITY: { std::string path = - target->GetLocalGenerator()->GetCurrentBinaryDirectory() + - std::string("/") + target->GetName(); - outputs.push_back(this->ConvertToNinjaPath(path)); + cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/', + target->GetName()); + std::string output = this->ConvertToNinjaPath(path); + if (target->Target->IsPerConfig()) { + output = this->BuildAlias(output, config); + } + outputs.push_back(output); break; } @@ -962,15 +1122,17 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( void cmGlobalNinjaGenerator::AppendTargetDepends( cmGeneratorTarget const* target, cmNinjaDeps& outputs, + const std::string& config, const std::string& fileConfig, cmNinjaTargetDepends depends) { if (target->GetType() == cmStateEnums::GLOBAL_TARGET) { // These depend only on other CMake-provided targets, e.g. "all". - for (BT<std::string> const& util : target->GetUtilities()) { + for (BT<std::pair<std::string, bool>> const& util : + target->GetUtilities()) { std::string d = - target->GetLocalGenerator()->GetCurrentBinaryDirectory() + "/" + - util.Value; - outputs.push_back(this->ConvertToNinjaPath(d)); + cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/', + util.Value.first); + outputs.push_back(this->BuildAlias(this->ConvertToNinjaPath(d), config)); } } else { cmNinjaDeps outs; @@ -979,29 +1141,36 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( if (targetDep->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - this->AppendTargetOutputs(targetDep, outs, depends); + if (targetDep.IsCross()) { + this->AppendTargetOutputs(targetDep, outs, fileConfig, depends); + } else { + this->AppendTargetOutputs(targetDep, outs, config, depends); + } } std::sort(outs.begin(), outs.end()); - cmAppend(outputs, outs); + cm::append(outputs, outs); } } void cmGlobalNinjaGenerator::AppendTargetDependsClosure( - cmGeneratorTarget const* target, cmNinjaDeps& outputs) + cmGeneratorTarget const* target, cmNinjaDeps& outputs, + const std::string& config) { cmNinjaOuts outs; - this->AppendTargetDependsClosure(target, outs, true); - cmAppend(outputs, outs); + this->AppendTargetDependsClosure(target, outs, config, true); + cm::append(outputs, outs); } void cmGlobalNinjaGenerator::AppendTargetDependsClosure( - cmGeneratorTarget const* target, cmNinjaOuts& outputs, bool omit_self) + cmGeneratorTarget const* target, cmNinjaOuts& outputs, + const std::string& config, bool omit_self) { // try to locate the target in the cache - auto find = this->TargetDependsClosures.lower_bound(target); + auto find = this->Configs[config].TargetDependsClosures.lower_bound(target); - if (find == this->TargetDependsClosures.end() || find->first != target) { + if (find == this->Configs[config].TargetDependsClosures.end() || + find->first != target) { // We now calculate the closure outputs by inspecting the dependent // targets recursively. // For that we have to distinguish between a local result set that is only @@ -1011,15 +1180,16 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure( cmNinjaOuts this_outs; // this will be the new cache entry for (auto const& dep_target : this->GetTargetDirectDepends(target)) { - if (dep_target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (dep_target->GetType() == cmStateEnums::INTERFACE_LIBRARY || + (this->EnableCrossConfigBuild() && !dep_target.IsCross())) { continue; } // Collect the dependent targets for _this_ target - this->AppendTargetDependsClosure(dep_target, this_outs, false); + this->AppendTargetDependsClosure(dep_target, this_outs, config, false); } - find = this->TargetDependsClosures.emplace_hint(find, target, - std::move(this_outs)); + find = this->Configs[config].TargetDependsClosures.emplace_hint( + find, target, std::move(this_outs)); } // now fill the outputs of the final result from the newly generated cache @@ -1029,29 +1199,56 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure( // finally generate the outputs of the target itself, if applicable cmNinjaDeps outs; if (!omit_self) { - this->AppendTargetOutputs(target, outs); + this->AppendTargetOutputs(target, outs, config); } outputs.insert(outs.begin(), outs.end()); } void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias, - cmGeneratorTarget* target) + cmGeneratorTarget* target, + const std::string& config) { - std::string buildAlias = this->NinjaOutputPath(alias); + std::string outputPath = this->NinjaOutputPath(alias); + std::string buildAlias = this->BuildAlias(outputPath, config); cmNinjaDeps outputs; - this->AppendTargetOutputs(target, outputs); - // Mark the target's outputs as ambiguous to ensure that no other target uses - // the output as an alias. + this->AppendTargetOutputs(target, outputs, config); + // Mark the target's outputs as ambiguous to ensure that no other target + // uses the output as an alias. for (std::string const& output : outputs) { - TargetAliases[output] = nullptr; + this->TargetAliases[output].GeneratorTarget = nullptr; + this->DefaultTargetAliases[output].GeneratorTarget = nullptr; + for (const std::string& config2 : + this->Makefiles.front()->GetGeneratorConfigs()) { + this->Configs[config2].TargetAliases[output].GeneratorTarget = nullptr; + } } // Insert the alias into the map. If the alias was already present in the // map and referred to another target, mark it as ambiguous. - std::pair<TargetAliasMap::iterator, bool> newAlias = - TargetAliases.insert(std::make_pair(buildAlias, target)); - if (newAlias.second && newAlias.first->second != target) { - newAlias.first->second = nullptr; + TargetAlias ta; + ta.GeneratorTarget = target; + ta.Config = config; + + auto newAliasGlobal = + this->TargetAliases.insert(std::make_pair(buildAlias, ta)); + if (newAliasGlobal.second && + newAliasGlobal.first->second.GeneratorTarget != target) { + newAliasGlobal.first->second.GeneratorTarget = nullptr; + } + + auto newAliasConfig = + this->Configs[config].TargetAliases.insert(std::make_pair(outputPath, ta)); + if (newAliasConfig.second && + newAliasConfig.first->second.GeneratorTarget != target) { + newAliasConfig.first->second.GeneratorTarget = nullptr; + } + if (this->DefaultConfigs.count(config)) { + auto newAliasDefaultGlobal = + this->DefaultTargetAliases.insert(std::make_pair(outputPath, ta)); + if (newAliasDefaultGlobal.second && + newAliasDefaultGlobal.first->second.GeneratorTarget != target) { + newAliasDefaultGlobal.first->second.GeneratorTarget = nullptr; + } } } @@ -1061,10 +1258,10 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) os << "# Target aliases.\n\n"; cmNinjaBuild build("phony"); - build.Outputs.emplace_back(""); - for (auto const& ta : TargetAliases) { + build.Outputs.emplace_back(); + for (auto const& ta : this->TargetAliases) { // Don't write ambiguous aliases. - if (!ta.second) { + if (!ta.second.GeneratorTarget) { continue; } @@ -1074,13 +1271,69 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) continue; } - // Outputs - build.Outputs[0] = ta.first; - // Explicit depdendencies + build.Outputs.front() = ta.first; build.ExplicitDeps.clear(); - this->AppendTargetOutputs(ta.second, build.ExplicitDeps); - // Write - this->WriteBuild(os, build); + if (ta.second.Config == "all") { + for (auto const& config : this->CrossConfigs) { + this->AppendTargetOutputs(ta.second.GeneratorTarget, + build.ExplicitDeps, config); + } + } else { + this->AppendTargetOutputs(ta.second.GeneratorTarget, build.ExplicitDeps, + ta.second.Config); + } + this->WriteBuild(this->EnableCrossConfigBuild() && + (ta.second.Config == "all" || + this->CrossConfigs.count(ta.second.Config)) + ? os + : *this->GetImplFileStream(ta.second.Config), + build); + } + + if (this->IsMultiConfig()) { + for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs()) { + for (auto const& ta : this->Configs[config].TargetAliases) { + // Don't write ambiguous aliases. + if (!ta.second.GeneratorTarget) { + continue; + } + + // Don't write alias if there is a already a custom command with + // matching output + if (this->HasCustomCommandOutput(ta.first)) { + continue; + } + + build.Outputs.front() = ta.first; + build.ExplicitDeps.clear(); + this->AppendTargetOutputs(ta.second.GeneratorTarget, + build.ExplicitDeps, config); + this->WriteBuild(*this->GetConfigFileStream(config), build); + } + } + + if (!this->DefaultConfigs.empty()) { + for (auto const& ta : this->DefaultTargetAliases) { + // Don't write ambiguous aliases. + if (!ta.second.GeneratorTarget) { + continue; + } + + // Don't write alias if there is a already a custom command with + // matching output + if (this->HasCustomCommandOutput(ta.first)) { + continue; + } + + build.Outputs.front() = ta.first; + build.ExplicitDeps.clear(); + for (auto const& config : this->DefaultConfigs) { + this->AppendTargetOutputs(ta.second.GeneratorTarget, + build.ExplicitDeps, config); + } + this->WriteBuild(*this->GetDefaultFileStream(), build); + } + } } } @@ -1097,24 +1350,70 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) cmGlobalNinjaGenerator::WriteDivider(os); std::string const& currentBinaryDir = it.first; DirectoryTarget const& dt = it.second; + std::vector<std::string> configs; + dt.LG->GetMakefile()->GetConfigurations(configs, true); + if (configs.empty()) { + configs.emplace_back(); + } // Setup target - build.Comment = "Folder: " + currentBinaryDir; - build.Outputs.emplace_back( - this->ConvertToNinjaPath(currentBinaryDir + "/all")); - for (DirectoryTarget::Target const& t : dt.Targets) { - if (!t.ExcludeFromAll) { - this->AppendTargetOutputs(t.GT, build.ExplicitDeps); + cmNinjaDeps configDeps; + build.Comment = cmStrCat("Folder: ", currentBinaryDir); + build.Outputs.emplace_back(); + std::string const buildDirAllTarget = + this->ConvertToNinjaPath(cmStrCat(currentBinaryDir, "/all")); + for (auto const& config : configs) { + build.ExplicitDeps.clear(); + build.Outputs.front() = this->BuildAlias(buildDirAllTarget, config); + configDeps.emplace_back(build.Outputs.front()); + for (DirectoryTarget::Target const& t : dt.Targets) { + if (!t.ExcludeFromAll) { + this->AppendTargetOutputs(t.GT, build.ExplicitDeps, config); + } } + for (DirectoryTarget::Dir const& d : dt.Children) { + if (!d.ExcludeFromAll) { + build.ExplicitDeps.emplace_back(this->BuildAlias( + this->ConvertToNinjaPath(cmStrCat(d.Path, "/all")), config)); + } + } + // Write target + this->WriteBuild(this->EnableCrossConfigBuild() && + this->CrossConfigs.count(config) + ? os + : *this->GetImplFileStream(config), + build); } - for (DirectoryTarget::Dir const& d : dt.Children) { - if (!d.ExcludeFromAll) { - build.ExplicitDeps.emplace_back( - this->ConvertToNinjaPath(d.Path + "/all")); + + // Add shortcut target + if (this->IsMultiConfig()) { + for (auto const& config : configs) { + build.ExplicitDeps = { this->BuildAlias(buildDirAllTarget, config) }; + build.Outputs.front() = buildDirAllTarget; + this->WriteBuild(*this->GetConfigFileStream(config), build); + } + + if (!this->DefaultFileConfig.empty()) { + build.ExplicitDeps.clear(); + for (auto const& config : this->DefaultConfigs) { + build.ExplicitDeps.push_back( + this->BuildAlias(buildDirAllTarget, config)); + } + build.Outputs.front() = buildDirAllTarget; + this->WriteBuild(*this->GetDefaultFileStream(), build); } } - // Write target - this->WriteBuild(os, build); + + // Add target for all configs + if (this->EnableCrossConfigBuild()) { + build.ExplicitDeps.clear(); + for (auto const& config : this->CrossConfigs) { + build.ExplicitDeps.push_back( + this->BuildAlias(buildDirAllTarget, config)); + } + build.Outputs.front() = this->BuildAlias(buildDirAllTarget, "all"); + this->WriteBuild(os, build); + } } } @@ -1148,7 +1447,7 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os) // get the list of files that cmake itself has generated as a // product of configuration. - for (cmLocalGenerator* lg : this->LocalGenerators) { + for (const auto& lg : this->LocalGenerators) { // get the vector of files created by this makefile and convert them // to ninja paths, which are all relative in respect to the build directory for (std::string const& file : lg->GetMakefile()->GetOutputFiles()) { @@ -1161,8 +1460,7 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os) knownDependencies.insert(this->ConvertToNinjaPath(j)); } } - for (cmGeneratorExpressionEvaluationFile* li : - lg->GetMakefile()->GetEvaluationFiles()) { + for (const auto& li : lg->GetMakefile()->GetEvaluationFiles()) { // get all the files created by generator expressions and convert them // to ninja paths for (std::string const& evaluationFile : li->GetFiles()) { @@ -1247,10 +1545,17 @@ void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os) cmGlobalNinjaGenerator::WriteDivider(os); os << "# Built-in targets\n\n"; - this->WriteTargetDefault(os); this->WriteTargetRebuildManifest(os); this->WriteTargetClean(os); this->WriteTargetHelp(os); + + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + this->WriteTargetDefault(*this->GetConfigFileStream(config)); + } + + if (!this->DefaultFileConfig.empty()) { + this->WriteTargetDefault(*this->GetDefaultFileStream()); + } } void cmGlobalNinjaGenerator::WriteTargetDefault(std::ostream& os) @@ -1268,12 +1573,12 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) { return; } - cmLocalGenerator* lg = this->LocalGenerators[0]; + const auto& lg = this->LocalGenerators[0]; { cmNinjaRule rule("RERUN_CMAKE"); rule.Command = - cmStrCat(CMakeCmd(), " -S", + cmStrCat(CMakeCmd(), " --regenerate-during-build -S", lg->ConvertToOutputFormat(lg->GetSourceDirectory(), cmOutputConverter::SHELL), " -B", @@ -1287,9 +1592,9 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) cmNinjaBuild reBuild("RERUN_CMAKE"); reBuild.Comment = "Re-run CMake if any of its inputs changed."; - reBuild.Outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE)); + this->AddRebuildManifestOutputs(reBuild.Outputs); - for (cmLocalGenerator* localGen : this->LocalGenerators) { + for (const auto& localGen : this->LocalGenerators) { for (std::string const& fi : localGen->GetMakefile()->GetListFiles()) { reBuild.ImplicitDeps.push_back(this->ConvertToNinjaPath(fi)); } @@ -1318,7 +1623,8 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) cmNinjaBuild phonyBuild("phony"); phonyBuild.Comment = "Phony target to force glob verification run."; - phonyBuild.Outputs.push_back(cm->GetGlobVerifyScript() + "_force"); + phonyBuild.Outputs.push_back( + cmStrCat(cm->GetGlobVerifyScript(), "_force")); this->WriteBuild(os, phonyBuild); reBuild.Variables["restat"] = "1"; @@ -1376,14 +1682,14 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) std::string cmGlobalNinjaGenerator::CMakeCmd() const { - cmLocalGenerator* lgen = this->LocalGenerators.at(0); + const auto& lgen = this->LocalGenerators.at(0); return lgen->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); } std::string cmGlobalNinjaGenerator::NinjaCmd() const { - cmLocalGenerator* lgen = this->LocalGenerators[0]; + const auto& lgen = this->LocalGenerators[0]; if (lgen != nullptr) { return lgen->ConvertToOutputFormat(this->NinjaCommand, cmOutputConverter::SHELL); @@ -1413,13 +1719,27 @@ bool cmGlobalNinjaGenerator::SupportsMultilineDepfile() const bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) { - cmLocalGenerator* lgr = this->LocalGenerators.at(0); + const auto& lgr = this->LocalGenerators.at(0); std::string cleanScriptRel = "CMakeFiles/clean_additional.cmake"; std::string cleanScriptAbs = cmStrCat(lgr->GetBinaryDirectory(), '/', cleanScriptRel); + std::vector<std::string> configs; + this->Makefiles[0]->GetConfigurations(configs, true); + if (configs.empty()) { + configs.emplace_back(); + } // Check if there are additional files to clean - if (this->AdditionalCleanFiles.empty()) { + bool empty = true; + for (auto const& config : configs) { + auto const it = this->Configs.find(config); + if (it != this->Configs.end() && + !it->second.AdditionalCleanFiles.empty()) { + empty = false; + break; + } + } + if (empty) { // Remove cmake clean script file if it exists cmSystemTools::RemoveFile(cleanScriptAbs); return false; @@ -1431,14 +1751,23 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) if (!fout) { return false; } - fout << "# Additional clean files\n\n"; - fout << "file(REMOVE_RECURSE\n"; - for (std::string const& acf : this->AdditionalCleanFiles) { - fout << " " - << cmOutputConverter::EscapeForCMake(ConvertToNinjaPath(acf)) - << '\n'; + fout << "# Additional clean files\ncmake_minimum_required(VERSION 3.16)\n"; + for (auto const& config : configs) { + auto const it = this->Configs.find(config); + if (it != this->Configs.end() && + !it->second.AdditionalCleanFiles.empty()) { + fout << "\nif(\"${CONFIG}\" STREQUAL \"\" OR \"${CONFIG}\" STREQUAL \"" + << config << "\")\n"; + fout << " file(REMOVE_RECURSE\n"; + for (std::string const& acf : it->second.AdditionalCleanFiles) { + fout << " " + << cmOutputConverter::EscapeForCMake(ConvertToNinjaPath(acf)) + << '\n'; + } + fout << " )\n"; + fout << "endif()\n"; + } } - fout << ")\n"; } // Register clean script file lgr->GetMakefile()->AddCMakeOutputFile(cleanScriptAbs); @@ -1447,7 +1776,7 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) { cmNinjaRule rule("CLEAN_ADDITIONAL"); rule.Command = cmStrCat( - CMakeCmd(), " -P ", + CMakeCmd(), " -DCONFIG=$CONFIG -P ", lgr->ConvertToOutputFormat(this->NinjaOutputPath(cleanScriptRel), cmOutputConverter::SHELL)); rule.Description = "Cleaning additional files..."; @@ -1459,9 +1788,19 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) { cmNinjaBuild build("CLEAN_ADDITIONAL"); build.Comment = "Clean additional files."; - build.Outputs.push_back( - this->NinjaOutputPath(this->GetAdditionalCleanTargetName())); - WriteBuild(os, build); + build.Outputs.emplace_back(); + for (auto const& config : configs) { + build.Outputs.front() = this->BuildAlias( + this->NinjaOutputPath(this->GetAdditionalCleanTargetName()), config); + build.Variables["CONFIG"] = config; + WriteBuild(os, build); + } + if (this->IsMultiConfig()) { + build.Outputs.front() = + this->NinjaOutputPath(this->GetAdditionalCleanTargetName()); + build.Variables["CONFIG"] = ""; + WriteBuild(os, build); + } } // Return success return true; @@ -1476,22 +1815,113 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) // Write rule { cmNinjaRule rule("CLEAN"); - rule.Command = NinjaCmd() + " -t clean"; + rule.Command = cmStrCat(NinjaCmd(), " $FILE_ARG -t clean $TARGETS"); rule.Description = "Cleaning all built files..."; rule.Comment = "Rule for cleaning all built files."; WriteRule(*this->RulesFileStream, rule); } + auto const configs = this->Makefiles.front()->GetGeneratorConfigs(); + // Write build { cmNinjaBuild build("CLEAN"); build.Comment = "Clean all the built files."; - build.Outputs.push_back(this->NinjaOutputPath(this->GetCleanTargetName())); - if (additionalFiles) { - build.ExplicitDeps.push_back( - this->NinjaOutputPath(this->GetAdditionalCleanTargetName())); + build.Outputs.emplace_back(); + + for (auto const& config : configs) { + build.Outputs.front() = this->BuildAlias( + this->NinjaOutputPath(this->GetCleanTargetName()), config); + if (this->IsMultiConfig()) { + build.Variables["TARGETS"] = + cmStrCat(this->BuildAlias(GetByproductsForCleanTargetName(), config), + " ", GetByproductsForCleanTargetName()); + } + build.ExplicitDeps.clear(); + if (additionalFiles) { + build.ExplicitDeps.push_back(this->BuildAlias( + this->NinjaOutputPath(this->GetAdditionalCleanTargetName()), + config)); + } + for (auto const& fileConfig : configs) { + if (fileConfig != config && !this->EnableCrossConfigBuild()) { + continue; + } + if (this->IsMultiConfig()) { + build.Variables["FILE_ARG"] = cmStrCat( + "-f ", + cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig)); + } + this->WriteBuild(*this->GetImplFileStream(fileConfig), build); + } } + + if (this->EnableCrossConfigBuild()) { + build.Outputs.front() = this->BuildAlias( + this->NinjaOutputPath(this->GetCleanTargetName()), "all"); + build.ExplicitDeps.clear(); + + if (additionalFiles) { + for (auto const& config : this->CrossConfigs) { + build.ExplicitDeps.push_back(this->BuildAlias( + this->NinjaOutputPath(this->GetAdditionalCleanTargetName()), + config)); + } + } + + std::vector<std::string> byproducts; + for (auto const& config : this->CrossConfigs) { + byproducts.push_back( + this->BuildAlias(GetByproductsForCleanTargetName(), config)); + } + build.Variables["TARGETS"] = cmJoin(byproducts, " "); + + for (auto const& fileConfig : configs) { + build.Variables["FILE_ARG"] = cmStrCat( + "-f ", + cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig)); + this->WriteBuild(*this->GetImplFileStream(fileConfig), build); + } + } + } + + if (this->IsMultiConfig()) { + cmNinjaBuild build("phony"); + build.Outputs.emplace_back( + this->NinjaOutputPath(this->GetCleanTargetName())); + build.ExplicitDeps.emplace_back(); + + for (auto const& config : configs) { + build.ExplicitDeps.front() = this->BuildAlias( + this->NinjaOutputPath(this->GetCleanTargetName()), config); + this->WriteBuild(*this->GetConfigFileStream(config), build); + } + + if (!this->DefaultConfigs.empty()) { + build.ExplicitDeps.clear(); + for (auto const& config : this->DefaultConfigs) { + build.ExplicitDeps.push_back(this->BuildAlias( + this->NinjaOutputPath(this->GetCleanTargetName()), config)); + } + this->WriteBuild(*this->GetDefaultFileStream(), build); + } + } + + // Write byproducts + if (this->IsMultiConfig()) { + cmNinjaBuild build("phony"); + build.Comment = "Clean byproducts."; + build.Outputs.emplace_back( + this->ConvertToNinjaPath(GetByproductsForCleanTargetName())); + build.ExplicitDeps = this->ByproductsForCleanTarget; WriteBuild(os, build); + + for (auto const& config : configs) { + build.Outputs.front() = this->BuildAlias( + this->ConvertToNinjaPath(GetByproductsForCleanTargetName()), config); + build.ExplicitDeps = this->Configs[config].ByproductsForCleanTarget; + WriteBuild(os, build); + } } } @@ -1499,7 +1929,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os) { { cmNinjaRule rule("HELP"); - rule.Command = NinjaCmd() + " -t targets"; + rule.Command = cmStrCat(NinjaCmd(), " -t targets"); rule.Description = "All primary targets available:"; rule.Comment = "Rule for printing all primary targets available."; WriteRule(*this->RulesFileStream, rule); @@ -1526,7 +1956,7 @@ std::string cmGlobalNinjaGenerator::NinjaOutputPath( if (!this->HasOutputPathPrefix() || cmSystemTools::FileIsFullPath(path)) { return path; } - return this->OutputPathPrefix + path; + return cmStrCat(this->OutputPathPrefix, path); } void cmGlobalNinjaGenerator::StripNinjaOutputPathPrefixAsSuffix( @@ -1654,7 +2084,8 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, } else if (cmHasLiteralPrefix(arg, "--lang=")) { arg_lang = arg.substr(7); } else { - cmSystemTools::Error("-E cmake_ninja_depends unknown argument: " + arg); + cmSystemTools::Error( + cmStrCat("-E cmake_ninja_depends unknown argument: ", arg)); return 1; } } @@ -1725,7 +2156,8 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, cmGeneratedFileStream ddif(arg_ddi); ddif << ddi; if (!ddif) { - cmSystemTools::Error("-E cmake_ninja_depends failed to write " + arg_ddi); + cmSystemTools::Error( + cmStrCat("-E cmake_ninja_depends failed to write ", arg_ddi)); return 1; } return 0; @@ -1771,7 +2203,8 @@ std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran( std::set<std::string> defines; cmFortranParser parser(fc, includes, defines, finfo); if (!cmFortranParser_FilePush(&parser, arg_pp.c_str())) { - cmSystemTools::Error("-E cmake_ninja_depends failed to open " + arg_pp); + cmSystemTools::Error( + cmStrCat("-E cmake_ninja_depends failed to open ", arg_pp)); return nullptr; } if (cmFortran_yyparse(parser.Scanner) != 0) { @@ -1809,11 +2242,9 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( snapshot.GetDirectory().SetRelativePathTopSource(dir_top_src.c_str()); snapshot.GetDirectory().SetRelativePathTopBinary(dir_top_bld.c_str()); auto mfd = cm::make_unique<cmMakefile>(this, snapshot); - std::unique_ptr<cmLocalNinjaGenerator> lgd( - static_cast<cmLocalNinjaGenerator*>( - this->CreateLocalGenerator(mfd.get()))); - this->Makefiles.push_back(mfd.release()); - this->LocalGenerators.push_back(lgd.release()); + auto lgd = this->CreateLocalGenerator(mfd.get()); + this->Makefiles.push_back(std::move(mfd)); + this->LocalGenerators.push_back(std::move(lgd)); } std::vector<cmDyndepObjectInfo> objects; @@ -1876,7 +2307,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( Json::Value tm = Json::objectValue; for (cmDyndepObjectInfo const& object : objects) { for (std::string const& p : object.Provides) { - std::string const mod = module_dir + p; + std::string const mod = cmStrCat(module_dir, p); mod_files[p] = mod; tm[p] = mod; } @@ -1912,14 +2343,19 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( // Store the map of modules provided by this target in a file for // use by dependents that reference this target in linked-target-dirs. - std::string const target_mods_file = - cmSystemTools::GetFilenamePath(arg_dd) + "/" + arg_lang + "Modules.json"; + std::string const target_mods_file = cmStrCat( + cmSystemTools::GetFilenamePath(arg_dd), '/', arg_lang, "Modules.json"); cmGeneratedFileStream tmf(target_mods_file); tmf << tm; return true; } +bool cmGlobalNinjaGenerator::EnableCrossConfigBuild() const +{ + return !this->CrossConfigs.empty(); +} + int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, std::vector<std::string>::const_iterator argEnd) { @@ -1941,7 +2377,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, cmHasLiteralSuffix(arg, ".ddi")) { arg_ddis.push_back(arg); } else { - cmSystemTools::Error("-E cmake_ninja_dyndep unknown argument: " + arg); + cmSystemTools::Error( + cmStrCat("-E cmake_ninja_dyndep unknown argument: ", arg)); return 1; } } @@ -1977,7 +2414,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, std::string const dir_top_src = tdi["dir-top-src"].asString(); std::string module_dir = tdi["module-dir"].asString(); if (!module_dir.empty() && !cmHasLiteralSuffix(module_dir, "/")) { - module_dir += "/"; + module_dir += '/'; } std::vector<std::string> linked_target_dirs; Json::Value const& tdi_linked_target_dirs = tdi["linked-target-dirs"]; @@ -1990,13 +2427,264 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, cmake cm(cmake::RoleInternal, cmState::Unknown); cm.SetHomeDirectory(dir_top_src); cm.SetHomeOutputDirectory(dir_top_bld); - std::unique_ptr<cmGlobalNinjaGenerator> ggd( - static_cast<cmGlobalNinjaGenerator*>(cm.CreateGlobalGenerator("Ninja"))); + auto ggd = cm.CreateGlobalGenerator("Ninja"); if (!ggd || - !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)) { + !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)) { return 1; } return 0; } + +void cmGlobalNinjaGenerator::AppendDirectoryForConfig( + const std::string& prefix, const std::string& config, + const std::string& suffix, std::string& dir) +{ + if (!config.empty() && this->IsMultiConfig()) { + dir += cmStrCat(prefix, config, suffix); + } +} + +std::set<std::string> cmGlobalNinjaGenerator::GetCrossConfigs( + const std::string& fileConfig) const +{ + auto result = this->CrossConfigs; + result.insert(fileConfig); + return result; +} + +const char* cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE = + "CMakeFiles/common.ninja"; +const char* cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION = ".ninja"; + +cmGlobalNinjaMultiGenerator::cmGlobalNinjaMultiGenerator(cmake* cm) + : cmGlobalNinjaGenerator(cm) +{ + cm->GetState()->SetIsGeneratorMultiConfig(true); + cm->GetState()->SetNinjaMulti(true); +} + +void cmGlobalNinjaMultiGenerator::GetDocumentation(cmDocumentationEntry& entry) +{ + entry.Name = cmGlobalNinjaMultiGenerator::GetActualName(); + entry.Brief = "Generates build-<Config>.ninja files."; +} + +std::string cmGlobalNinjaMultiGenerator::ExpandCFGIntDir( + const std::string& str, const std::string& config) const +{ + std::string result = str; + cmSystemTools::ReplaceString(result, this->GetCMakeCFGIntDir(), config); + return result; +} + +bool cmGlobalNinjaMultiGenerator::OpenBuildFileStreams() +{ + if (!this->OpenFileStream(this->CommonFileStream, + cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE)) { + return false; + } + + if (!this->DefaultFileConfig.empty()) { + if (!this->OpenFileStream(this->DefaultFileStream, NINJA_BUILD_FILE)) { + return false; + } + *this->DefaultFileStream + << "# Build using rules for '" << this->DefaultFileConfig << "'.\n\n" + << "include " << GetNinjaImplFilename(this->DefaultFileConfig) << "\n\n"; + } + + // Write a comment about this file. + *this->CommonFileStream + << "# This file contains build statements common to all " + "configurations.\n\n"; + + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + // Open impl file. + if (!this->OpenFileStream(this->ImplFileStreams[config], + GetNinjaImplFilename(config))) { + return false; + } + + // Write a comment about this file. + *this->ImplFileStreams[config] + << "# This file contains build statements specific to the \"" << config + << "\"\n# configuration.\n\n"; + + // Open config file. + if (!this->OpenFileStream(this->ConfigFileStreams[config], + GetNinjaConfigFilename(config))) { + return false; + } + + // Write a comment about this file. + *this->ConfigFileStreams[config] + << "# This file contains aliases specific to the \"" << config + << "\"\n# configuration.\n\n" + << "include " << GetNinjaImplFilename(config) << "\n\n"; + } + + return true; +} + +void cmGlobalNinjaMultiGenerator::CloseBuildFileStreams() +{ + if (this->CommonFileStream) { + this->CommonFileStream.reset(); + } else { + cmSystemTools::Error("Common file stream was not open."); + } + + if (this->DefaultFileStream) { + this->DefaultFileStream.reset(); + } // No error if it wasn't open + + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + if (this->ImplFileStreams[config]) { + this->ImplFileStreams[config].reset(); + } else { + cmSystemTools::Error( + cmStrCat("Impl file stream for \"", config, "\" was not open.")); + } + if (this->ConfigFileStreams[config]) { + this->ConfigFileStreams[config].reset(); + } else { + cmSystemTools::Error( + cmStrCat("Config file stream for \"", config, "\" was not open.")); + } + } +} + +void cmGlobalNinjaMultiGenerator::AppendNinjaFileArgument( + GeneratedMakeCommand& command, const std::string& config) const +{ + if (!config.empty()) { + command.Add("-f"); + command.Add(GetNinjaConfigFilename(config)); + } +} + +std::string cmGlobalNinjaMultiGenerator::GetNinjaImplFilename( + const std::string& config) +{ + return cmStrCat("CMakeFiles/impl-", config, + cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION); +} + +std::string cmGlobalNinjaMultiGenerator::GetNinjaConfigFilename( + const std::string& config) +{ + return cmStrCat("build-", config, + cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION); +} + +void cmGlobalNinjaMultiGenerator::AddRebuildManifestOutputs( + cmNinjaDeps& outputs) const +{ + for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs()) { + outputs.push_back(this->NinjaOutputPath(GetNinjaImplFilename(config))); + outputs.push_back(this->NinjaOutputPath(GetNinjaConfigFilename(config))); + } + if (!this->DefaultFileConfig.empty()) { + outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE)); + } +} + +void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs( + std::vector<std::string>& configs) const +{ + auto const oldSize = configs.size(); + this->Makefiles.front()->GetConfigurations(configs); + if (configs.size() == oldSize) { + configs.emplace_back(); + } +} + +bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables() +{ + this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_BUILD_TYPE"); + this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_CROSS_CONFIGS"); + this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_CONFIGS"); + return this->ReadCacheEntriesForBuild(*this->Makefiles.front()->GetState()); +} + +std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const +{ + return ""; +} + +bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( + const cmState& state) +{ + std::vector<std::string> configsVec; + cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CONFIGURATION_TYPES"), + configsVec); + if (configsVec.empty()) { + configsVec.emplace_back(); + } + std::set<std::string> configs(configsVec.cbegin(), configsVec.cend()); + + this->DefaultFileConfig = + state.GetSafeCacheEntryValue("CMAKE_DEFAULT_BUILD_TYPE"); + if (this->DefaultFileConfig.empty()) { + this->DefaultFileConfig = configsVec.front(); + } + if (!configs.count(this->DefaultFileConfig)) { + std::ostringstream msg; + msg << "The configuration specified by " + << "CMAKE_DEFAULT_BUILD_TYPE (" << this->DefaultFileConfig + << ") is not present in CMAKE_CONFIGURATION_TYPES"; + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, + msg.str()); + return false; + } + + std::vector<std::string> crossConfigsVec; + cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CROSS_CONFIGS"), + crossConfigsVec); + auto crossConfigs = ListSubsetWithAll(configs, configs, crossConfigsVec); + if (!crossConfigs) { + std::ostringstream msg; + msg << "CMAKE_CROSS_CONFIGS is not a subset of " + << "CMAKE_CONFIGURATION_TYPES"; + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, + msg.str()); + return false; + } + this->CrossConfigs = *crossConfigs; + + auto defaultConfigsString = + state.GetSafeCacheEntryValue("CMAKE_DEFAULT_CONFIGS"); + if (defaultConfigsString.empty()) { + defaultConfigsString = this->DefaultFileConfig; + } + if (!defaultConfigsString.empty() && + defaultConfigsString != this->DefaultFileConfig && + (this->DefaultFileConfig.empty() || this->CrossConfigs.empty())) { + std::ostringstream msg; + msg << "CMAKE_DEFAULT_CONFIGS cannot be used without " + << "CMAKE_DEFAULT_BUILD_TYPE or CMAKE_CROSS_CONFIGS"; + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, + msg.str()); + return false; + } + + std::vector<std::string> defaultConfigsVec; + cmExpandList(defaultConfigsString, defaultConfigsVec); + if (!this->DefaultFileConfig.empty()) { + auto defaultConfigs = + ListSubsetWithAll(this->GetCrossConfigs(this->DefaultFileConfig), + this->CrossConfigs, defaultConfigsVec); + if (!defaultConfigs) { + std::ostringstream msg; + msg << "CMAKE_DEFAULT_CONFIGS is not a subset of CMAKE_CROSS_CONFIGS"; + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, + msg.str()); + return false; + } + this->DefaultConfigs = *defaultConfigs; + } + + return true; +} diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 244e9fd..5668dd1 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -15,6 +15,8 @@ #include <utility> #include <vector> +#include <cm/optional> + #include "cm_codecvt.hxx" #include "cmGeneratedFileStream.h" @@ -22,6 +24,7 @@ #include "cmGlobalGeneratorFactory.h" #include "cmNinjaTypes.h" #include "cmPolicies.h" +#include "cmStringAlgorithms.h" class cmCustomCommand; class cmGeneratorTarget; @@ -29,6 +32,7 @@ class cmLinkLineComputer; class cmLocalGenerator; class cmMakefile; class cmOutputConverter; +class cmState; class cmStateDirectory; class cmake; struct cmDocumentationEntry; @@ -73,10 +77,10 @@ public: static void WriteDivider(std::ostream& os); static std::string EncodeRuleName(std::string const& name); - static std::string EncodeLiteral(const std::string& lit); + std::string EncodeLiteral(const std::string& lit); std::string EncodePath(const std::string& path); - cmLinkLineComputer* CreateLinkLineComputer( + std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer( cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const override; @@ -111,11 +115,12 @@ public: const std::string& command, const std::string& description, const std::string& comment, const std::string& depfile, const std::string& pool, bool uses_terminal, bool restat, - const cmNinjaDeps& outputs, + const cmNinjaDeps& outputs, const std::string& config, const cmNinjaDeps& explicitDeps = cmNinjaDeps(), const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps()); - void WriteMacOSXContentBuild(std::string input, std::string output); + void WriteMacOSXContentBuild(std::string input, std::string output, + const std::string& config); /** * Write a rule statement to @a os. @@ -151,12 +156,14 @@ public: public: cmGlobalNinjaGenerator(cmake* cm); - static cmGlobalGeneratorFactory* NewFactory() + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() { - return new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaGenerator>(); + return std::unique_ptr<cmGlobalGeneratorFactory>( + new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaGenerator>()); } - cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override; + std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( + cmMakefile* mf) override; std::string GetName() const override { @@ -204,7 +211,26 @@ public: } const char* GetCleanTargetName() const override { return "clean"; } - cmGeneratedFileStream* GetBuildFileStream() const + bool SupportsCustomCommandDepfile() const override { return true; } + + virtual cmGeneratedFileStream* GetImplFileStream( + const std::string& /*config*/) const + { + return this->BuildFileStream.get(); + } + + virtual cmGeneratedFileStream* GetConfigFileStream( + const std::string& /*config*/) const + { + return this->BuildFileStream.get(); + } + + virtual cmGeneratedFileStream* GetDefaultFileStream() const + { + return this->BuildFileStream.get(); + } + + virtual cmGeneratedFileStream* GetCommonFileStream() const { return this->BuildFileStream.get(); } @@ -231,12 +257,17 @@ public: MapToNinjaPathImpl MapToNinjaPath() { return { this }; } // -- Additional clean files - void AddAdditionalCleanFile(std::string fileName); + void AddAdditionalCleanFile(std::string fileName, const std::string& config); const char* GetAdditionalCleanTargetName() const { return "CMakeFiles/clean.additional"; } + static const char* GetByproductsForCleanTargetName() + { + return "CMakeFiles/cmake_byproducts_for_clean_target"; + } + void AddCXXCompileCommand(const std::string& commandLine, const std::string& sourceFile); @@ -260,9 +291,9 @@ public: /// Called when we have seen the given custom command. Returns true /// if we has seen it before. - bool SeenCustomCommand(cmCustomCommand const* cc) + bool SeenCustomCommand(cmCustomCommand const* cc, const std::string& config) { - return !this->CustomCommands.insert(cc).second; + return !this->Configs[config].CustomCommands.insert(cc).second; } /// Called when we have seen the given custom command output. @@ -284,25 +315,43 @@ public: ASD.insert(deps.begin(), deps.end()); } + static std::string OrderDependsTargetForTarget( + cmGeneratorTarget const* target, const std::string& config); + void AppendTargetOutputs( cmGeneratorTarget const* target, cmNinjaDeps& outputs, + const std::string& config, cmNinjaTargetDepends depends = DependOnTargetArtifact); void AppendTargetDepends( cmGeneratorTarget const* target, cmNinjaDeps& outputs, + const std::string& config, const std::string& fileConfig, cmNinjaTargetDepends depends = DependOnTargetArtifact); void AppendTargetDependsClosure(cmGeneratorTarget const* target, - cmNinjaDeps& outputs); + cmNinjaDeps& outputs, + const std::string& config); void AppendTargetDependsClosure(cmGeneratorTarget const* target, - cmNinjaOuts& outputs, bool omit_self); + cmNinjaOuts& outputs, + const std::string& config, bool omit_self); + + void AppendDirectoryForConfig(const std::string& prefix, + const std::string& config, + const std::string& suffix, + std::string& dir) override; - const std::vector<cmLocalGenerator*>& GetLocalGenerators() const + virtual void AppendNinjaFileArgument(GeneratedMakeCommand& /*command*/, + const std::string& /*config*/) const { - return LocalGenerators; + } + + virtual void AddRebuildManifestOutputs(cmNinjaDeps& outputs) const + { + outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE)); } int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; } - void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target); + void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target, + const std::string& config); void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override; @@ -316,6 +365,12 @@ public: return "1.9"; } static std::string RequiredNinjaVersionForDyndeps() { return "1.10"; } + static std::string RequiredNinjaVersionForRestatTool() { return "1.10"; } + static std::string RequiredNinjaVersionForUnconditionalRecompactTool() + { + return "1.10"; + } + static std::string RequiredNinjaVersionForCleanDeadTool() { return "1.10"; } bool SupportsConsolePool() const; bool SupportsImplicitOuts() const; bool SupportsManifestRestat() const; @@ -335,11 +390,52 @@ public: std::vector<std::string> const& linked_target_dirs, std::string const& arg_lang); + virtual std::string BuildAlias(const std::string& alias, + const std::string& /*config*/) const + { + return alias; + } + + virtual std::string ConfigDirectory(const std::string& /*config*/) const + { + return ""; + } + + cmNinjaDeps& GetByproductsForCleanTarget() + { + return this->ByproductsForCleanTarget; + } + + cmNinjaDeps& GetByproductsForCleanTarget(const std::string& config) + { + return this->Configs[config].ByproductsForCleanTarget; + } + + bool EnableCrossConfigBuild() const; + + std::set<std::string> GetCrossConfigs(const std::string& config) const; + protected: void Generate() override; bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const override { return true; } + virtual bool OpenBuildFileStreams(); + virtual void CloseBuildFileStreams(); + + bool OpenFileStream(std::unique_ptr<cmGeneratedFileStream>& stream, + const std::string& name); + + static cm::optional<std::set<std::string>> ListSubsetWithAll( + const std::set<std::string>& all, const std::set<std::string>& defaults, + const std::vector<std::string>& items); + + virtual bool InspectConfigTypeVariables() { return true; } + + std::set<std::string> CrossConfigs; + std::set<std::string> DefaultConfigs; + std::string DefaultFileConfig; + private: std::string GetEditCacheCommand() const override; bool FindMakeProgram(cmMakefile* mf) override; @@ -348,13 +444,11 @@ private: cmMakefile* mf) const override; bool CheckFortran(cmMakefile* mf) const; - bool OpenBuildFileStream(); - void CloseBuildFileStream(); - void CloseCompileCommandsStream(); bool OpenRulesFileStream(); void CloseRulesFileStream(); + void CleanMetaData(); /// Write the common disclaimer text at the top of each build file. void WriteDisclaimer(std::ostream& os); @@ -395,9 +489,6 @@ private: bool UsingGCCOnWindows = false; - /// The set of custom commands we have seen. - std::set<cmCustomCommand const*> CustomCommands; - /// The set of custom command outputs we have seen. std::set<std::string> CustomCommandOutputs; @@ -416,10 +507,14 @@ private: /// The mapping from source file to assumed dependencies. std::map<std::string, std::set<std::string>> AssumedSourceDependencies; - using TargetAliasMap = std::map<std::string, cmGeneratorTarget*>; + struct TargetAlias + { + cmGeneratorTarget* GeneratorTarget; + std::string Config; + }; + using TargetAliasMap = std::map<std::string, TargetAlias>; TargetAliasMap TargetAliases; - - std::map<cmGeneratorTarget const*, cmNinjaOuts> TargetDependsClosures; + TargetAliasMap DefaultTargetAliases; /// the local cache for calls to ConvertToNinjaPath mutable std::unordered_map<std::string, std::string> ConvertToNinjaPathCache; @@ -431,6 +526,9 @@ private: bool NinjaSupportsManifestRestat = false; bool NinjaSupportsMultilineDepfile = false; bool NinjaSupportsDyndeps = false; + bool NinjaSupportsRestatTool = false; + bool NinjaSupportsUnconditionalRecompactTool = false; + bool NinjaSupportsCleanDeadTool = false; private: void InitOutputPathPrefix(); @@ -438,7 +536,125 @@ private: std::string OutputPathPrefix; std::string TargetAll; std::string CMakeCacheFile; - std::set<std::string> AdditionalCleanFiles; + + struct ByConfig + { + std::set<std::string> AdditionalCleanFiles; + + /// The set of custom commands we have seen. + std::set<cmCustomCommand const*> CustomCommands; + + std::map<cmGeneratorTarget const*, cmNinjaOuts> TargetDependsClosures; + + TargetAliasMap TargetAliases; + + cmNinjaDeps ByproductsForCleanTarget; + }; + std::map<std::string, ByConfig> Configs; + + cmNinjaDeps ByproductsForCleanTarget; +}; + +class cmGlobalNinjaMultiGenerator : public cmGlobalNinjaGenerator +{ +public: + /// The default name of Ninja's common file. Typically: common.ninja. + static const char* NINJA_COMMON_FILE; + /// The default file extension to use for per-config Ninja files. + static const char* NINJA_FILE_EXTENSION; + + cmGlobalNinjaMultiGenerator(cmake* cm); + bool IsMultiConfig() const override { return true; } + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() + { + return std::unique_ptr<cmGlobalGeneratorFactory>( + new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaMultiGenerator>()); + } + + static void GetDocumentation(cmDocumentationEntry& entry); + + std::string GetName() const override + { + return cmGlobalNinjaMultiGenerator::GetActualName(); + } + + static std::string GetActualName() { return "Ninja Multi-Config"; } + + std::string BuildAlias(const std::string& alias, + const std::string& config) const override + { + if (config.empty()) { + return alias; + } + return cmStrCat(alias, ":", config); + } + + std::string ConfigDirectory(const std::string& config) const override + { + if (!config.empty()) { + return cmStrCat('/', config); + } + return ""; + } + + const char* GetCMakeCFGIntDir() const override { return "${CONFIGURATION}"; } + + std::string ExpandCFGIntDir(const std::string& str, + const std::string& config) const override; + + cmGeneratedFileStream* GetImplFileStream( + const std::string& config) const override + { + return this->ImplFileStreams.at(config).get(); + } + + cmGeneratedFileStream* GetConfigFileStream( + const std::string& config) const override + { + return this->ConfigFileStreams.at(config).get(); + } + + cmGeneratedFileStream* GetDefaultFileStream() const override + { + return this->DefaultFileStream.get(); + } + + cmGeneratedFileStream* GetCommonFileStream() const override + { + return this->CommonFileStream.get(); + } + + void AppendNinjaFileArgument(GeneratedMakeCommand& command, + const std::string& config) const override; + + static std::string GetNinjaImplFilename(const std::string& config); + static std::string GetNinjaConfigFilename(const std::string& config); + + void AddRebuildManifestOutputs(cmNinjaDeps& outputs) const override; + + void GetQtAutoGenConfigs(std::vector<std::string>& configs) const override; + + bool InspectConfigTypeVariables() override; + + std::string GetDefaultBuildConfig() const override; + + bool ReadCacheEntriesForBuild(const cmState& state) override; + + bool SupportsDefaultBuildType() const override { return true; } + bool SupportsCrossConfigs() const override { return true; } + bool SupportsDefaultConfigs() const override { return true; } + +protected: + bool OpenBuildFileStreams() override; + void CloseBuildFileStreams() override; + +private: + std::map<std::string, std::unique_ptr<cmGeneratedFileStream>> + ImplFileStreams; + std::map<std::string, std::unique_ptr<cmGeneratedFileStream>> + ConfigFileStreams; + std::unique_ptr<cmGeneratedFileStream> CommonFileStream; + std::unique_ptr<cmGeneratedFileStream> DefaultFileStream; }; #endif // ! cmGlobalNinjaGenerator_h diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 4c2d69f..7daca74 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -8,8 +8,9 @@ #include <utility> #include <cm/memory> +#include <cmext/algorithm> +#include <cmext/memory> -#include "cmAlgorithms.h" #include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" @@ -40,7 +41,6 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm) #else this->UseLinkScript = true; #endif - this->CommandDatabase = nullptr; this->IncludeDirective = "include"; this->DefineWindowsNULL = false; @@ -48,6 +48,8 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm) this->UnixCD = true; } +cmGlobalUnixMakefileGenerator3::~cmGlobalUnixMakefileGenerator3() = default; + void cmGlobalUnixMakefileGenerator3::EnableLanguage( std::vector<std::string> const& languages, cmMakefile* mf, bool optional) { @@ -61,10 +63,11 @@ void cmGlobalUnixMakefileGenerator3::EnableLanguage( } //! Create a local generator appropriate to this Global Generator -cmLocalGenerator* cmGlobalUnixMakefileGenerator3::CreateLocalGenerator( - cmMakefile* mf) +std::unique_ptr<cmLocalGenerator> +cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(cmMakefile* mf) { - return new cmLocalUnixMakefileGenerator3(this, mf); + return std::unique_ptr<cmLocalGenerator>( + cm::make_unique<cmLocalUnixMakefileGenerator3>(this, mf)); } void cmGlobalUnixMakefileGenerator3::GetDocumentation( @@ -144,21 +147,20 @@ void cmGlobalUnixMakefileGenerator3::Generate() for (auto& pmi : this->ProgressMap) { pmi.second.WriteProgressVariables(total, current); } - for (cmLocalGenerator* lg : this->LocalGenerators) { + for (const auto& lg : this->LocalGenerators) { std::string markFileName = cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles/progress.marks"); cmGeneratedFileStream markFile(markFileName); - markFile << this->CountProgressMarksInAll(lg) << "\n"; + markFile << this->CountProgressMarksInAll(*lg) << "\n"; } // write the main makefile this->WriteMainMakefile2(); this->WriteMainCMakefile(); - if (this->CommandDatabase != nullptr) { + if (this->CommandDatabase) { *this->CommandDatabase << std::endl << "]"; - delete this->CommandDatabase; - this->CommandDatabase = nullptr; + this->CommandDatabase.reset(); } } @@ -166,11 +168,12 @@ void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand( const std::string& sourceFile, const std::string& workingDirectory, const std::string& compileCommand) { - if (this->CommandDatabase == nullptr) { + if (!this->CommandDatabase) { std::string commandDatabaseName = this->GetCMakeInstance()->GetHomeOutputDirectory() + "/compile_commands.json"; - this->CommandDatabase = new cmGeneratedFileStream(commandDatabaseName); + this->CommandDatabase = + cm::make_unique<cmGeneratedFileStream>(commandDatabaseName); *this->CommandDatabase << "[" << std::endl; } else { *this->CommandDatabase << "," << std::endl; @@ -203,11 +206,11 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() } // get a local generator for some useful methods - cmLocalUnixMakefileGenerator3* lg = - static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]); + auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>( + this->LocalGenerators[0]); // Write the do not edit header. - lg->WriteDisclaimer(makefileStream); + lg.WriteDisclaimer(makefileStream); // Write the main entry point target. This must be the VERY first // target so that make with no arguments will run it. @@ -217,10 +220,10 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() depends.emplace_back("all"); // Write the rule. - lg->WriteMakeRule(makefileStream, - "Default target executed when no arguments are " - "given to make.", - "default_target", depends, no_commands, true); + lg.WriteMakeRule(makefileStream, + "Default target executed when no arguments are " + "given to make.", + "default_target", depends, no_commands, true); depends.clear(); @@ -231,7 +234,7 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() } // Write out the "special" stuff - lg->WriteSpecialTargetsTop(makefileStream); + lg.WriteSpecialTargetsTop(makefileStream); // Write the directory level rules. for (auto const& it : this->ComputeDirectoryTargets()) { @@ -239,13 +242,14 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() } // Write the target convenience rules - for (cmLocalGenerator* localGen : this->LocalGenerators) { + for (const auto& localGen : this->LocalGenerators) { this->WriteConvenienceRules2( - makefileStream, static_cast<cmLocalUnixMakefileGenerator3*>(localGen)); + makefileStream, + cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen)); } // Write special bottom targets - lg->WriteSpecialTargetsBottom(makefileStream); + lg.WriteSpecialTargetsBottom(makefileStream); } void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() @@ -268,12 +272,14 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() std::string makefileName = cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), "/Makefile"); - // get a local generator for some useful methods - cmLocalUnixMakefileGenerator3* lg = - static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]); + { + // get a local generator for some useful methods + auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>( + this->LocalGenerators[0]); - // Write the do not edit header. - lg->WriteDisclaimer(cmakefileStream); + // Write the do not edit header. + lg.WriteDisclaimer(cmakefileStream); + } // Save the generator name cmakefileStream << "# The generator used is:\n" @@ -282,9 +288,9 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() // for each cmMakefile get its list of dependencies std::vector<std::string> lfiles; - for (cmLocalGenerator* localGen : this->LocalGenerators) { + for (const auto& localGen : this->LocalGenerators) { // Get the list of files contributing to this generation step. - cmAppend(lfiles, localGen->GetMakefile()->GetListFiles()); + cm::append(lfiles, localGen->GetMakefile()->GetListFiles()); } cmake* cm = this->GetCMakeInstance(); @@ -300,59 +306,60 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() lfiles.erase(new_end, lfiles.end()); #endif - // reset lg to the first makefile - lg = static_cast<cmLocalUnixMakefileGenerator3*>(this->LocalGenerators[0]); - - std::string currentBinDir = lg->GetCurrentBinaryDirectory(); - // Save the list to the cmake file. - cmakefileStream - << "# The top level Makefile was generated from the following files:\n" - << "set(CMAKE_MAKEFILE_DEPENDS\n" - << " \"CMakeCache.txt\"\n"; - for (std::string const& f : lfiles) { - cmakefileStream << " \"" - << lg->MaybeConvertToRelativePath(currentBinDir, f) - << "\"\n"; - } - cmakefileStream << " )\n\n"; - - // Build the path to the cache check file. - std::string check = - cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), - "/CMakeFiles/cmake.check_cache"); - - // Set the corresponding makefile in the cmake file. - cmakefileStream << "# The corresponding makefile is:\n" - << "set(CMAKE_MAKEFILE_OUTPUTS\n" - << " \"" - << lg->MaybeConvertToRelativePath(currentBinDir, - makefileName) - << "\"\n" - << " \"" - << lg->MaybeConvertToRelativePath(currentBinDir, check) - << "\"\n"; - cmakefileStream << " )\n\n"; - - const std::string binDir = lg->GetBinaryDirectory(); - - // CMake must rerun if a byproduct is missing. { - cmakefileStream << "# Byproducts of CMake generate step:\n" - << "set(CMAKE_MAKEFILE_PRODUCTS\n"; - for (std::string const& outfile : lg->GetMakefile()->GetOutputFiles()) { + // reset lg to the first makefile + const auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>( + this->LocalGenerators[0]); + + const std::string& currentBinDir = lg.GetCurrentBinaryDirectory(); + // Save the list to the cmake file. + cmakefileStream + << "# The top level Makefile was generated from the following files:\n" + << "set(CMAKE_MAKEFILE_DEPENDS\n" + << " \"CMakeCache.txt\"\n"; + for (std::string const& f : lfiles) { cmakefileStream << " \"" - << lg->MaybeConvertToRelativePath(binDir, outfile) + << lg.MaybeConvertToRelativePath(currentBinDir, f) << "\"\n"; } + cmakefileStream << " )\n\n"; + + // Build the path to the cache check file. + std::string check = + cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), + "/CMakeFiles/cmake.check_cache"); + + // Set the corresponding makefile in the cmake file. + cmakefileStream << "# The corresponding makefile is:\n" + << "set(CMAKE_MAKEFILE_OUTPUTS\n" + << " \"" + << lg.MaybeConvertToRelativePath(currentBinDir, + makefileName) + << "\"\n" + << " \"" + << lg.MaybeConvertToRelativePath(currentBinDir, check) + << "\"\n"; + cmakefileStream << " )\n\n"; - // add in all the directory information files + const std::string& binDir = lg.GetBinaryDirectory(); + + // CMake must rerun if a byproduct is missing. + cmakefileStream << "# Byproducts of CMake generate step:\n" + << "set(CMAKE_MAKEFILE_PRODUCTS\n"; + + // add in any byproducts and all the directory information files std::string tmpStr; - for (cmLocalGenerator* localGen : this->LocalGenerators) { - lg = static_cast<cmLocalUnixMakefileGenerator3*>(localGen); - tmpStr = cmStrCat(lg->GetCurrentBinaryDirectory(), + for (const auto& localGen : this->LocalGenerators) { + for (std::string const& outfile : + localGen->GetMakefile()->GetOutputFiles()) { + cmakefileStream << " \"" + << lg.MaybeConvertToRelativePath(binDir, outfile) + << "\"\n"; + } + tmpStr = cmStrCat(localGen->GetCurrentBinaryDirectory(), "/CMakeFiles/CMakeDirectoryInformation.cmake"); cmakefileStream << " \"" - << lg->MaybeConvertToRelativePath(binDir, tmpStr) + << localGen->MaybeConvertToRelativePath(binDir, tmpStr) << "\"\n"; } cmakefileStream << " )\n\n"; @@ -364,26 +371,24 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules( cmGeneratedFileStream& cmakefileStream, - std::vector<cmLocalGenerator*>& lGenerators) + std::vector<std::unique_ptr<cmLocalGenerator>>& lGenerators) { - cmLocalUnixMakefileGenerator3* lg; - // now list all the target info files cmakefileStream << "# Dependency information for all targets:\n"; cmakefileStream << "set(CMAKE_DEPEND_INFO_FILES\n"; - for (cmLocalGenerator* lGenerator : lGenerators) { - lg = static_cast<cmLocalUnixMakefileGenerator3*>(lGenerator); + for (const auto& lGenerator : lGenerators) { + const auto& lg = + cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(lGenerator); // for all of out targets - for (cmGeneratorTarget* tgt : lg->GetGeneratorTargets()) { + for (const auto& tgt : lg.GetGeneratorTargets()) { if ((tgt->GetType() == cmStateEnums::EXECUTABLE) || (tgt->GetType() == cmStateEnums::STATIC_LIBRARY) || (tgt->GetType() == cmStateEnums::SHARED_LIBRARY) || (tgt->GetType() == cmStateEnums::MODULE_LIBRARY) || (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) || (tgt->GetType() == cmStateEnums::UTILITY)) { - cmGeneratorTarget* gt = tgt; - std::string tname = - cmStrCat(lg->GetRelativeTargetDirectory(gt), "/DependInfo.cmake"); + std::string tname = cmStrCat(lg.GetRelativeTargetDirectory(tgt.get()), + "/DependInfo.cmake"); cmSystemTools::ConvertToUnixSlashes(tname); cmakefileStream << " \"" << tname << "\"\n"; } @@ -487,7 +492,7 @@ cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( std::unique_ptr<cmMakefile> mfu; cmMakefile* mf; if (!this->Makefiles.empty()) { - mf = this->Makefiles[0]; + mf = this->Makefiles[0].get(); } else { cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot(); snapshot.GetDirectory().SetCurrentSource( @@ -545,11 +550,11 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules( } // write the target convenience rules - for (cmLocalGenerator* localGen : this->LocalGenerators) { - cmLocalUnixMakefileGenerator3* lg = - static_cast<cmLocalUnixMakefileGenerator3*>(localGen); + for (const auto& localGen : this->LocalGenerators) { + auto& lg = + cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen); // for each target Generate the rule files for each target. - for (cmGeneratorTarget* gtarget : lg->GetGeneratorTargets()) { + for (const auto& gtarget : lg.GetGeneratorTargets()) { // Don't emit the same rule twice (e.g. two targets with the same // simple name) int type = gtarget->GetType(); @@ -564,23 +569,23 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules( (type == cmStateEnums::OBJECT_LIBRARY) || (type == cmStateEnums::UTILITY))) { // Add a rule to build the target by name. - lg->WriteDivider(ruleFileStream); + lg.WriteDivider(ruleFileStream); ruleFileStream << "# Target rules for targets named " << name << "\n\n"; // Write the rule. commands.clear(); std::string tmp = "CMakeFiles/Makefile2"; - commands.push_back(lg->GetRecursiveMakeCall(tmp, name)); + commands.push_back(lg.GetRecursiveMakeCall(tmp, name)); depends.clear(); if (regenerate) { depends.emplace_back("cmake_check_build_system"); } - lg->WriteMakeRule(ruleFileStream, "Build rule for target.", name, - depends, commands, true); + lg.WriteMakeRule(ruleFileStream, "Build rule for target.", name, + depends, commands, true); // Add a fast rule to build the target - std::string localName = lg->GetRelativeTargetDirectory(gtarget); + std::string localName = lg.GetRelativeTargetDirectory(gtarget.get()); std::string makefileName; makefileName = cmStrCat(localName, "/build.make"); depends.clear(); @@ -588,23 +593,23 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules( std::string makeTargetName = cmStrCat(localName, "/build"); localName = cmStrCat(name, "/fast"); commands.push_back( - lg->GetRecursiveMakeCall(makefileName, makeTargetName)); - lg->WriteMakeRule(ruleFileStream, "fast build rule for target.", - localName, depends, commands, true); + lg.GetRecursiveMakeCall(makefileName, makeTargetName)); + lg.WriteMakeRule(ruleFileStream, "fast build rule for target.", + localName, depends, commands, true); // Add a local name for the rule to relink the target before // installation. - if (gtarget->NeedRelinkBeforeInstall(lg->GetConfigName())) { - makeTargetName = - cmStrCat(lg->GetRelativeTargetDirectory(gtarget), "/preinstall"); + if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) { + makeTargetName = cmStrCat( + lg.GetRelativeTargetDirectory(gtarget.get()), "/preinstall"); localName = cmStrCat(name, "/preinstall"); depends.clear(); commands.clear(); commands.push_back( - lg->GetRecursiveMakeCall(makefileName, makeTargetName)); - lg->WriteMakeRule(ruleFileStream, - "Manual pre-install relink rule for target.", - localName, depends, commands, true); + lg.GetRecursiveMakeCall(makefileName, makeTargetName)); + lg.WriteMakeRule(ruleFileStream, + "Manual pre-install relink rule for target.", + localName, depends, commands, true); } } } @@ -612,7 +617,7 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules( } void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( - std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg) + std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& lg) { std::vector<std::string> depends; std::vector<std::string> commands; @@ -625,7 +630,7 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( } // for each target Generate the rule files for each target. - for (cmGeneratorTarget* gtarget : lg->GetGeneratorTargets()) { + for (const auto& gtarget : lg.GetGeneratorTargets()) { int type = gtarget->GetType(); std::string name = gtarget->GetName(); if (!name.empty() && @@ -637,31 +642,31 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( (type == cmStateEnums::UTILITY))) { std::string makefileName; // Add a rule to build the target by name. - localName = lg->GetRelativeTargetDirectory(gtarget); + localName = lg.GetRelativeTargetDirectory(gtarget.get()); makefileName = cmStrCat(localName, "/build.make"); - lg->WriteDivider(ruleFileStream); + lg.WriteDivider(ruleFileStream); ruleFileStream << "# Target rules for target " << localName << "\n\n"; commands.clear(); makeTargetName = cmStrCat(localName, "/depend"); commands.push_back( - lg->GetRecursiveMakeCall(makefileName, makeTargetName)); + lg.GetRecursiveMakeCall(makefileName, makeTargetName)); makeTargetName = cmStrCat(localName, "/build"); commands.push_back( - lg->GetRecursiveMakeCall(makefileName, makeTargetName)); + lg.GetRecursiveMakeCall(makefileName, makeTargetName)); // Write the rule. localName += "/all"; depends.clear(); cmLocalUnixMakefileGenerator3::EchoProgress progress; - progress.Dir = cmStrCat(lg->GetBinaryDirectory(), "/CMakeFiles"); + progress.Dir = cmStrCat(lg.GetBinaryDirectory(), "/CMakeFiles"); { std::ostringstream progressArg; const char* sep = ""; - for (unsigned long progFile : this->ProgressMap[gtarget].Marks) { + for (unsigned long progFile : this->ProgressMap[gtarget.get()].Marks) { progressArg << sep << progFile; sep = ","; } @@ -676,13 +681,13 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( } if (targetMessages) { - lg->AppendEcho(commands, "Built target " + name, - cmLocalUnixMakefileGenerator3::EchoNormal, &progress); + lg.AppendEcho(commands, "Built target " + name, + cmLocalUnixMakefileGenerator3::EchoNormal, &progress); } - this->AppendGlobalTargetDepends(depends, gtarget); - lg->WriteMakeRule(ruleFileStream, "All Build rule for target.", - localName, depends, commands, true); + this->AppendGlobalTargetDepends(depends, gtarget.get()); + lg.WriteMakeRule(ruleFileStream, "All Build rule for target.", localName, + depends, commands, true); // Write the rule. commands.clear(); @@ -692,20 +697,21 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # in target - progCmd << lg->ConvertToOutputFormat( + progCmd << lg.ConvertToOutputFormat( cmSystemTools::CollapseFullPath(progress.Dir), cmOutputConverter::SHELL); // std::set<cmGeneratorTarget const*> emitted; - progCmd << " " << this->CountProgressMarksInTarget(gtarget, emitted); + progCmd << " " + << this->CountProgressMarksInTarget(gtarget.get(), emitted); commands.push_back(progCmd.str()); } std::string tmp = "CMakeFiles/Makefile2"; - commands.push_back(lg->GetRecursiveMakeCall(tmp, localName)); + commands.push_back(lg.GetRecursiveMakeCall(tmp, localName)); { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << lg->ConvertToOutputFormat( + progCmd << lg.ConvertToOutputFormat( cmSystemTools::CollapseFullPath(progress.Dir), cmOutputConverter::SHELL); progCmd << " 0"; @@ -715,39 +721,39 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( if (regenerate) { depends.emplace_back("cmake_check_build_system"); } - localName = cmStrCat(lg->GetRelativeTargetDirectory(gtarget), "/rule"); - lg->WriteMakeRule(ruleFileStream, - "Build rule for subdir invocation for target.", - localName, depends, commands, true); + localName = + cmStrCat(lg.GetRelativeTargetDirectory(gtarget.get()), "/rule"); + lg.WriteMakeRule(ruleFileStream, + "Build rule for subdir invocation for target.", + localName, depends, commands, true); // Add a target with the canonical name (no prefix, suffix or path). commands.clear(); depends.clear(); depends.push_back(localName); - lg->WriteMakeRule(ruleFileStream, "Convenience name for target.", name, - depends, commands, true); + lg.WriteMakeRule(ruleFileStream, "Convenience name for target.", name, + depends, commands, true); // Add rules to prepare the target for installation. - if (gtarget->NeedRelinkBeforeInstall(lg->GetConfigName())) { - localName = - cmStrCat(lg->GetRelativeTargetDirectory(gtarget), "/preinstall"); + if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) { + localName = cmStrCat(lg.GetRelativeTargetDirectory(gtarget.get()), + "/preinstall"); depends.clear(); commands.clear(); - commands.push_back(lg->GetRecursiveMakeCall(makefileName, localName)); - lg->WriteMakeRule(ruleFileStream, - "Pre-install relink rule for target.", localName, - depends, commands, true); + commands.push_back(lg.GetRecursiveMakeCall(makefileName, localName)); + lg.WriteMakeRule(ruleFileStream, "Pre-install relink rule for target.", + localName, depends, commands, true); } // add the clean rule - localName = lg->GetRelativeTargetDirectory(gtarget); + localName = lg.GetRelativeTargetDirectory(gtarget.get()); makeTargetName = cmStrCat(localName, "/clean"); depends.clear(); commands.clear(); commands.push_back( - lg->GetRecursiveMakeCall(makefileName, makeTargetName)); - lg->WriteMakeRule(ruleFileStream, "clean rule for target.", - makeTargetName, depends, commands, true); + lg.GetRecursiveMakeCall(makefileName, makeTargetName)); + lg.WriteMakeRule(ruleFileStream, "clean rule for target.", + makeTargetName, depends, commands, true); commands.clear(); } } @@ -759,8 +765,8 @@ void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks() { this->DirectoryTargetsMap.clear(); // Loop over all targets in all local generators. - for (cmLocalGenerator* lg : this->LocalGenerators) { - for (cmGeneratorTarget* gt : lg->GetGeneratorTargets()) { + for (const auto& lg : this->LocalGenerators) { + for (const auto& gt : lg->GetGeneratorTargets()) { cmLocalGenerator* tlg = gt->GetLocalGenerator(); if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY || @@ -778,12 +784,13 @@ void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks() // This local generator includes the target. std::set<cmGeneratorTarget const*>& targetSet = this->DirectoryTargetsMap[csnp]; - targetSet.insert(gt); + targetSet.insert(gt.get()); // Add dependencies of the included target. An excluded // target may still be included if it is a dependency of a // non-excluded target. - for (cmTargetDepend const& tgtdep : this->GetTargetDirectDepends(gt)) { + for (cmTargetDepend const& tgtdep : + this->GetTargetDirectDepends(gt.get())) { targetSet.insert(tgtdep); } } @@ -808,12 +815,12 @@ size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInTarget( } size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInAll( - cmLocalGenerator* lg) + const cmLocalGenerator& lg) { size_t count = 0; std::set<cmGeneratorTarget const*> emitted; for (cmGeneratorTarget const* target : - this->DirectoryTargetsMap[lg->GetStateSnapshot()]) { + this->DirectoryTargetsMap[lg.GetStateSnapshot()]) { count += this->CountProgressMarksInTarget(target, emitted); } return count; @@ -885,33 +892,48 @@ void cmGlobalUnixMakefileGenerator3::WriteHelpRule( // Keep track of targets already listed. std::set<std::string> emittedTargets; + std::set<std::string> utility_targets; + std::set<std::string> globals_targets; + std::set<std::string> project_targets; // for each local generator - for (cmLocalGenerator* localGen : this->LocalGenerators) { - cmLocalUnixMakefileGenerator3* lg2 = - static_cast<cmLocalUnixMakefileGenerator3*>(localGen); + for (const auto& localGen : this->LocalGenerators) { + const auto& lg2 = + cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen); // for the passed in makefile or if this is the top Makefile wripte out // the targets - if (lg2 == lg || lg->IsRootMakefile()) { + if (&lg2 == lg || lg->IsRootMakefile()) { // for each target Generate the rule files for each target. - for (cmGeneratorTarget* target : lg2->GetGeneratorTargets()) { + for (const auto& target : lg2.GetGeneratorTargets()) { cmStateEnums::TargetType type = target->GetType(); if ((type == cmStateEnums::EXECUTABLE) || (type == cmStateEnums::STATIC_LIBRARY) || (type == cmStateEnums::SHARED_LIBRARY) || (type == cmStateEnums::MODULE_LIBRARY) || - (type == cmStateEnums::OBJECT_LIBRARY) || - (type == cmStateEnums::GLOBAL_TARGET) || - (type == cmStateEnums::UTILITY)) { - std::string const& name = target->GetName(); - if (emittedTargets.insert(name).second) { - path = cmStrCat("... ", name); - lg->AppendEcho(commands, path); - } + (type == cmStateEnums::OBJECT_LIBRARY)) { + project_targets.insert(target->GetName()); + } else if (type == cmStateEnums::GLOBAL_TARGET) { + globals_targets.insert(target->GetName()); + } else if (type == cmStateEnums::UTILITY) { + utility_targets.insert(target->GetName()); } } } } + + for (std::string const& name : globals_targets) { + path = cmStrCat("... ", name); + lg->AppendEcho(commands, path); + } + for (std::string const& name : utility_targets) { + path = cmStrCat("... ", name); + lg->AppendEcho(commands, path); + } + for (std::string const& name : project_targets) { + path = cmStrCat("... ", name); + lg->AppendEcho(commands, path); + } + for (std::string const& o : lg->GetLocalHelp()) { path = cmStrCat("... ", o); lg->AppendEcho(commands, path); diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index 79db30e..19b2b85 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -8,6 +8,7 @@ #include <cstddef> #include <iosfwd> #include <map> +#include <memory> #include <set> #include <string> #include <vector> @@ -61,12 +62,19 @@ class cmGlobalUnixMakefileGenerator3 : public cmGlobalCommonGenerator { public: cmGlobalUnixMakefileGenerator3(cmake* cm); - static cmGlobalGeneratorFactory* NewFactory() + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() { - return new cmGlobalGeneratorSimpleFactory< - cmGlobalUnixMakefileGenerator3>(); + return std::unique_ptr<cmGlobalGeneratorFactory>( + new cmGlobalGeneratorSimpleFactory<cmGlobalUnixMakefileGenerator3>()); } + ~cmGlobalUnixMakefileGenerator3() override; + + cmGlobalUnixMakefileGenerator3(const cmGlobalUnixMakefileGenerator3&) = + delete; + cmGlobalUnixMakefileGenerator3& operator=( + const cmGlobalUnixMakefileGenerator3&) = delete; + //! Get the name for the generator. std::string GetName() const override { @@ -89,7 +97,8 @@ public: /** Get the documentation entry for this generator. */ static void GetDocumentation(cmDocumentationEntry& entry); - cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override; + std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( + cmMakefile* mf) override; /** * Try to determine system information such as shared library @@ -107,8 +116,9 @@ public: */ void Generate() override; - void WriteMainCMakefileLanguageRules(cmGeneratedFileStream& cmakefileStream, - std::vector<cmLocalGenerator*>&); + void WriteMainCMakefileLanguageRules( + cmGeneratedFileStream& cmakefileStream, + std::vector<std::unique_ptr<cmLocalGenerator>>&); // write out the help rule listing the valid targets void WriteHelpRule(std::ostream& ruleFileStream, @@ -161,7 +171,7 @@ protected: void WriteMainCMakefile(); void WriteConvenienceRules2(std::ostream& ruleFileStream, - cmLocalUnixMakefileGenerator3*); + cmLocalUnixMakefileGenerator3&); void WriteDirectoryRule2(std::ostream& ruleFileStream, DirectoryTarget const& dt, const char* pass, @@ -227,9 +237,9 @@ protected: size_t CountProgressMarksInTarget( cmGeneratorTarget const* target, std::set<cmGeneratorTarget const*>& emitted); - size_t CountProgressMarksInAll(cmLocalGenerator* lg); + size_t CountProgressMarksInAll(const cmLocalGenerator& lg); - cmGeneratedFileStream* CommandDatabase; + std::unique_ptr<cmGeneratedFileStream> CommandDatabase; private: const char* GetBuildIgnoreErrorsFlag() const override { return "-i"; } diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index f6472ab..ccb6c50 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -4,6 +4,8 @@ #include <algorithm> +#include <cm/memory> + #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" @@ -26,6 +28,16 @@ static const char vs10generatorName[] = "Visual Studio 10 2010"; static std::map<std::string, std::vector<cmIDEFlagTable>> loadedFlagJsonFiles; +static void ConvertToWindowsSlashes(std::string& s) +{ + // first convert all of the slashes + for (auto& ch : s) { + if (ch == '/') { + ch = '\\'; + } + } +} + // Map generator name without year to name with year. static const char* cmVS10GenName(const std::string& name, std::string& genName) { @@ -45,27 +57,30 @@ class cmGlobalVisualStudio10Generator::Factory : public cmGlobalGeneratorFactory { public: - cmGlobalGenerator* CreateGlobalGenerator(const std::string& name, - cmake* cm) const override + std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( + const std::string& name, cmake* cm) const override { std::string genName; const char* p = cmVS10GenName(name, genName); if (!p) { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } if (!*p) { - return new cmGlobalVisualStudio10Generator(cm, genName, ""); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio10Generator(cm, genName, "")); } if (*p++ != ' ') { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } if (strcmp(p, "Win64") == 0) { - return new cmGlobalVisualStudio10Generator(cm, genName, "x64"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio10Generator(cm, genName, "x64")); } if (strcmp(p, "IA64") == 0) { - return new cmGlobalVisualStudio10Generator(cm, genName, "Itanium"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio10Generator(cm, genName, "Itanium")); } - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } void GetDocumentation(cmDocumentationEntry& entry) const override @@ -105,9 +120,10 @@ public: std::string GetDefaultPlatformName() const override { return "Win32"; } }; -cmGlobalGeneratorFactory* cmGlobalVisualStudio10Generator::NewFactory() +std::unique_ptr<cmGlobalGeneratorFactory> +cmGlobalVisualStudio10Generator::NewFactory() { - return new Factory; + return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory); } cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator( @@ -193,7 +209,7 @@ static void cmCudaToolVersion(std::string& s) } bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( - std::string const& ts, cmMakefile* mf) + std::string const& ts, bool build, cmMakefile* mf) { if (this->SystemIsWindowsCE && ts.empty() && this->DefaultPlatformToolset.empty()) { @@ -208,7 +224,11 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( return false; } - if (!this->FindVCTargetsPath(mf)) { + if (build) { + return true; + } + + if (this->CustomVCTargetsPath.empty() && !this->FindVCTargetsPath(mf)) { return false; } @@ -355,6 +375,11 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( if (const char* cudaDir = this->GetPlatformToolsetCudaCustomDir()) { mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR", cudaDir); } + if (const char* vcTargetsDir = this->GetCustomVCTargetsPath()) { + mf->AddDefinition("CMAKE_VS_PLATFORM_TOOLSET_VCTARGETS_CUSTOM_DIR", + vcTargetsDir); + } + return true; } @@ -448,6 +473,11 @@ bool cmGlobalVisualStudio10Generator::ProcessGeneratorToolsetField( this->GeneratorToolsetVersion = value; return true; } + if (key == "VCTargetsPath") { + this->CustomVCTargetsPath = value; + ConvertToWindowsSlashes(this->CustomVCTargetsPath); + return true; + } return false; } @@ -556,10 +586,11 @@ std::string cmGlobalVisualStudio10Generator::SelectWindowsCEToolset() const } //! Create a local generator appropriate to this Global Generator -cmLocalGenerator* cmGlobalVisualStudio10Generator::CreateLocalGenerator( - cmMakefile* mf) +std::unique_ptr<cmLocalGenerator> +cmGlobalVisualStudio10Generator::CreateLocalGenerator(cmMakefile* mf) { - return new cmLocalVisualStudio10Generator(this, mf); + return std::unique_ptr<cmLocalGenerator>( + cm::make_unique<cmLocalVisualStudio10Generator>(this, mf)); } void cmGlobalVisualStudio10Generator::Generate() @@ -590,7 +621,7 @@ void cmGlobalVisualStudio10Generator::Generate() "To avoid this problem CMake must use a full path for this file " "which then triggers the VS 10 property dialog bug."; /* clang-format on */ - lg->IssueMessage(MessageType::WARNING, e.str().c_str()); + lg->IssueMessage(MessageType::WARNING, e.str()); } } @@ -609,6 +640,14 @@ void cmGlobalVisualStudio10Generator::EnableLanguage( cmGlobalVisualStudio8Generator::EnableLanguage(lang, mf, optional); } +const char* cmGlobalVisualStudio10Generator::GetCustomVCTargetsPath() const +{ + if (this->CustomVCTargetsPath.empty()) { + return nullptr; + } + return this->CustomVCTargetsPath.c_str(); +} + const char* cmGlobalVisualStudio10Generator::GetPlatformToolset() const { std::string const& toolset = this->GetPlatformToolsetString(); @@ -803,7 +842,7 @@ bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf) // Prepare the work directory. if (!cmSystemTools::MakeDirectory(wd)) { std::string e = "Failed to make directory:\n " + wd; - mf->IssueMessage(MessageType::FATAL_ERROR, e.c_str()); + mf->IssueMessage(MessageType::FATAL_ERROR, e); cmSystemTools::SetFatalErrorOccured(); return false; } @@ -924,7 +963,7 @@ bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf) if (ret != 0) { e << "Exit code: " << ret << "\n"; } - mf->IssueMessage(MessageType::FATAL_ERROR, e.str().c_str()); + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); cmSystemTools::SetFatalErrorOccured(); return false; } @@ -1098,8 +1137,7 @@ std::string cmGlobalVisualStudio10Generator::GenerateRuleFile( // Hide them away under the CMakeFiles directory. std::string ruleDir = cmStrCat( this->GetCMakeInstance()->GetHomeOutputDirectory(), "/CMakeFiles/", - cmSystemTools::ComputeStringMD5( - cmSystemTools::GetFilenamePath(output).c_str())); + cmSystemTools::ComputeStringMD5(cmSystemTools::GetFilenamePath(output))); std::string ruleFile = cmStrCat(ruleDir, '/', cmSystemTools::GetFilenameName(output), ".rule"); return ruleFile; @@ -1293,7 +1331,7 @@ cmIDEFlagTable const* cmGlobalVisualStudio10Generator::LoadFlagTable( e << "JSON flag table \"" << filename << "\" could not be loaded.\n"; /* clang-format on */ - mf->IssueMessage(MessageType::FATAL_ERROR, e.str().c_str()); + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); } return ret; } diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 56f1193..f659ff3 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -3,6 +3,8 @@ #ifndef cmGlobalVisualStudio10Generator_h #define cmGlobalVisualStudio10Generator_h +#include <memory> + #include "cmGlobalVisualStudio8Generator.h" #include "cmVisualStudio10ToolsetOptions.h" @@ -14,13 +16,14 @@ class cmGlobalVisualStudio10Generator : public cmGlobalVisualStudio8Generator { public: - static cmGlobalGeneratorFactory* NewFactory(); + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory(); bool MatchesGeneratorName(const std::string& name) const override; bool SetSystemName(std::string const& s, cmMakefile* mf) override; bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override; - bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override; + bool SetGeneratorToolset(std::string const& ts, bool build, + cmMakefile* mf) override; std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, @@ -30,7 +33,8 @@ public: std::vector<std::string>()) override; //! create the correct local generator - cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override; + std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( + cmMakefile* mf) override; /** * Try to determine system information such as shared library @@ -45,6 +49,9 @@ public: bool IsNsightTegra() const; std::string GetNsightTegraVersion() const; + /** The vctargets path for the target platform. */ + const char* GetCustomVCTargetsPath() const; + /** The toolset name for the target platform. */ const char* GetPlatformToolset() const; std::string const& GetPlatformToolsetString() const; @@ -157,6 +164,7 @@ protected: std::string GeneratorToolset; std::string GeneratorToolsetVersion; std::string GeneratorToolsetHostArchitecture; + std::string GeneratorToolsetCustomVCTargetsDir; std::string GeneratorToolsetCuda; std::string GeneratorToolsetCudaCustomDir; std::string DefaultPlatformToolset; @@ -209,6 +217,7 @@ private: bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf); + std::string CustomVCTargetsPath; std::string VCTargetsPath; bool FindVCTargetsPath(cmMakefile* mf); diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx index 4b74ef1..a385375 100644 --- a/Source/cmGlobalVisualStudio11Generator.cxx +++ b/Source/cmGlobalVisualStudio11Generator.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio11Generator.h" +#include <utility> + #include "cmAlgorithms.h" #include "cmDocumentationEntry.h" #include "cmLocalVisualStudio10Generator.h" @@ -28,38 +30,41 @@ class cmGlobalVisualStudio11Generator::Factory : public cmGlobalGeneratorFactory { public: - cmGlobalGenerator* CreateGlobalGenerator(const std::string& name, - cmake* cm) const override + std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( + const std::string& name, cmake* cm) const override { std::string genName; const char* p = cmVS11GenName(name, genName); if (!p) { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } if (!*p) { - return new cmGlobalVisualStudio11Generator(cm, genName, ""); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio11Generator(cm, genName, "")); } if (*p++ != ' ') { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } if (strcmp(p, "Win64") == 0) { - return new cmGlobalVisualStudio11Generator(cm, genName, "x64"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio11Generator(cm, genName, "x64")); } if (strcmp(p, "ARM") == 0) { - return new cmGlobalVisualStudio11Generator(cm, genName, "ARM"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio11Generator(cm, genName, "ARM")); } std::set<std::string> installedSDKs = cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs(); if (installedSDKs.find(p) == installedSDKs.end()) { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } - cmGlobalVisualStudio11Generator* ret = - new cmGlobalVisualStudio11Generator(cm, name, p); + auto ret = std::unique_ptr<cmGlobalVisualStudio11Generator>( + new cmGlobalVisualStudio11Generator(cm, name, p)); ret->WindowsCEVersion = "8.00"; - return ret; + return std::unique_ptr<cmGlobalGenerator>(std::move(ret)); } void GetDocumentation(cmDocumentationEntry& entry) const override @@ -113,9 +118,10 @@ public: std::string GetDefaultPlatformName() const override { return "Win32"; } }; -cmGlobalGeneratorFactory* cmGlobalVisualStudio11Generator::NewFactory() +std::unique_ptr<cmGlobalGeneratorFactory> +cmGlobalVisualStudio11Generator::NewFactory() { - return new Factory; + return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory); } cmGlobalVisualStudio11Generator::cmGlobalVisualStudio11Generator( diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h index f8cce18..5f1ff73 100644 --- a/Source/cmGlobalVisualStudio11Generator.h +++ b/Source/cmGlobalVisualStudio11Generator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <memory> #include <set> #include <string> @@ -20,7 +21,7 @@ class cmake; class cmGlobalVisualStudio11Generator : public cmGlobalVisualStudio10Generator { public: - static cmGlobalGeneratorFactory* NewFactory(); + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory(); bool MatchesGeneratorName(const std::string& name) const override; diff --git a/Source/cmGlobalVisualStudio12Generator.cxx b/Source/cmGlobalVisualStudio12Generator.cxx index d9702c9..5a27994 100644 --- a/Source/cmGlobalVisualStudio12Generator.cxx +++ b/Source/cmGlobalVisualStudio12Generator.cxx @@ -28,27 +28,30 @@ class cmGlobalVisualStudio12Generator::Factory : public cmGlobalGeneratorFactory { public: - cmGlobalGenerator* CreateGlobalGenerator(const std::string& name, - cmake* cm) const override + std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( + const std::string& name, cmake* cm) const override { std::string genName; const char* p = cmVS12GenName(name, genName); if (!p) { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } if (!*p) { - return new cmGlobalVisualStudio12Generator(cm, genName, ""); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio12Generator(cm, genName, "")); } if (*p++ != ' ') { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } if (strcmp(p, "Win64") == 0) { - return new cmGlobalVisualStudio12Generator(cm, genName, "x64"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio12Generator(cm, genName, "x64")); } if (strcmp(p, "ARM") == 0) { - return new cmGlobalVisualStudio12Generator(cm, genName, "ARM"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio12Generator(cm, genName, "ARM")); } - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } void GetDocumentation(cmDocumentationEntry& entry) const override @@ -88,9 +91,10 @@ public: std::string GetDefaultPlatformName() const override { return "Win32"; } }; -cmGlobalGeneratorFactory* cmGlobalVisualStudio12Generator::NewFactory() +std::unique_ptr<cmGlobalGeneratorFactory> +cmGlobalVisualStudio12Generator::NewFactory() { - return new Factory; + return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory); } cmGlobalVisualStudio12Generator::cmGlobalVisualStudio12Generator( diff --git a/Source/cmGlobalVisualStudio12Generator.h b/Source/cmGlobalVisualStudio12Generator.h index 53b7091..bdd40ff 100644 --- a/Source/cmGlobalVisualStudio12Generator.h +++ b/Source/cmGlobalVisualStudio12Generator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <memory> #include <string> #include "cmGlobalVisualStudio11Generator.h" @@ -18,7 +19,7 @@ class cmake; class cmGlobalVisualStudio12Generator : public cmGlobalVisualStudio11Generator { public: - static cmGlobalGeneratorFactory* NewFactory(); + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory(); bool MatchesGeneratorName(const std::string& name) const override; diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx index cd48474..f549b6a 100644 --- a/Source/cmGlobalVisualStudio14Generator.cxx +++ b/Source/cmGlobalVisualStudio14Generator.cxx @@ -2,7 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio14Generator.h" -#include "cmAlgorithms.h" +#include <cm/vector> + #include "cmDocumentationEntry.h" #include "cmLocalVisualStudio10Generator.h" #include "cmMakefile.h" @@ -28,27 +29,30 @@ class cmGlobalVisualStudio14Generator::Factory : public cmGlobalGeneratorFactory { public: - cmGlobalGenerator* CreateGlobalGenerator(const std::string& name, - cmake* cm) const override + std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( + const std::string& name, cmake* cm) const override { std::string genName; const char* p = cmVS14GenName(name, genName); if (!p) { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } if (!*p) { - return new cmGlobalVisualStudio14Generator(cm, genName, ""); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio14Generator(cm, genName, "")); } if (*p++ != ' ') { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } if (strcmp(p, "Win64") == 0) { - return new cmGlobalVisualStudio14Generator(cm, genName, "x64"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio14Generator(cm, genName, "x64")); } if (strcmp(p, "ARM") == 0) { - return new cmGlobalVisualStudio14Generator(cm, genName, "ARM"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio14Generator(cm, genName, "ARM")); } - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } void GetDocumentation(cmDocumentationEntry& entry) const override @@ -88,9 +92,10 @@ public: std::string GetDefaultPlatformName() const override { return "Win32"; } }; -cmGlobalGeneratorFactory* cmGlobalVisualStudio14Generator::NewFactory() +std::unique_ptr<cmGlobalGeneratorFactory> +cmGlobalVisualStudio14Generator::NewFactory() { - return new Factory; + return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory); } cmGlobalVisualStudio14Generator::cmGlobalVisualStudio14Generator( @@ -299,7 +304,7 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion() // Skip SDKs that do not contain <um/windows.h> because that indicates that // only the UCRT MSIs were installed for them. - cmEraseIf(sdks, NoWindowsH()); + cm::erase_if(sdks, NoWindowsH()); // Only use the filename, which will be the SDK version. for (std::string& i : sdks) { @@ -309,7 +314,7 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion() // Skip SDKs that cannot be used with our toolset. std::string maxVersion = this->GetWindows10SDKMaxVersion(); if (!maxVersion.empty()) { - cmEraseIf(sdks, WindowsSDKTooRecent(maxVersion)); + cm::erase_if(sdks, WindowsSDKTooRecent(maxVersion)); } // Sort the results to make sure we select the most recent one. diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h index 6e12d3e..ccc2917 100644 --- a/Source/cmGlobalVisualStudio14Generator.h +++ b/Source/cmGlobalVisualStudio14Generator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <memory> #include <string> #include "cmGlobalVisualStudio12Generator.h" @@ -18,7 +19,7 @@ class cmake; class cmGlobalVisualStudio14Generator : public cmGlobalVisualStudio12Generator { public: - static cmGlobalGeneratorFactory* NewFactory(); + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory(); bool MatchesGeneratorName(const std::string& name) const override; diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index e8e9ece..d0aec61 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -87,7 +87,7 @@ void cmGlobalVisualStudio71Generator::WriteSolutionConfigurations( // the libraries it uses are also done here void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout, const std::string& dspname, - const char* dir, + const std::string& dir, cmGeneratorTarget const* t) { // check to see if this is a fortran build @@ -109,7 +109,7 @@ void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout, std::string guid = this->GetGUID(dspname); fout << project << dspname << "\", \"" << this->ConvertToSolutionPath(dir) - << (dir[0] ? "\\" : "") << dspname << ext << "\", \"{" << guid + << (!dir.empty() ? "\\" : "") << dspname << ext << "\", \"{" << guid << "}\"\n"; fout << "\tProjectSection(ProjectDependencies) = postProject\n"; this->WriteProjectDepends(fout, dspname, dir, t); @@ -138,7 +138,7 @@ void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout, // Note, that dependencies from executables to // the libraries it uses are also done here void cmGlobalVisualStudio71Generator::WriteProjectDepends( - std::ostream& fout, const std::string&, const char*, + std::ostream& fout, const std::string&, const std::string&, cmGeneratorTarget const* target) { VSDependSet const& depends = this->VSTargetDepends[target]; @@ -156,8 +156,9 @@ void cmGlobalVisualStudio71Generator::WriteProjectDepends( // Write a dsp file into the SLN file, Note, that dependencies from // executables to the libraries it uses are also done here void cmGlobalVisualStudio71Generator::WriteExternalProject( - std::ostream& fout, const std::string& name, const char* location, - const char* typeGuid, const std::set<BT<std::string>>& depends) + std::ostream& fout, const std::string& name, const std::string& location, + const char* typeGuid, + const std::set<BT<std::pair<std::string, bool>>>& depends) { fout << "Project(\"{" << (typeGuid ? typeGuid : this->ExternalProjectType(location)) @@ -169,8 +170,8 @@ void cmGlobalVisualStudio71Generator::WriteExternalProject( // project instead of in the global section if (!depends.empty()) { fout << "\tProjectSection(ProjectDependencies) = postProject\n"; - for (BT<std::string> const& it : depends) { - std::string const& dep = it.Value; + for (BT<std::pair<std::string, bool>> const& it : depends) { + std::string const& dep = it.Value.first; if (!dep.empty()) { fout << "\t\t{" << this->GetGUID(dep) << "} = {" << this->GetGUID(dep) << "}\n"; diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h index 85755af..7eadaf3 100644 --- a/Source/cmGlobalVisualStudio71Generator.h +++ b/Source/cmGlobalVisualStudio71Generator.h @@ -22,18 +22,20 @@ protected: virtual void WriteSolutionConfigurations( std::ostream& fout, std::vector<std::string> const& configs); void WriteProject(std::ostream& fout, const std::string& name, - const char* path, const cmGeneratorTarget* t) override; + const std::string& path, + const cmGeneratorTarget* t) override; void WriteProjectDepends(std::ostream& fout, const std::string& name, - const char* path, + const std::string& path, cmGeneratorTarget const* t) override; void WriteProjectConfigurations( std::ostream& fout, const std::string& name, cmGeneratorTarget const& target, std::vector<std::string> const& configs, const std::set<std::string>& configsPartOfDefaultBuild, const std::string& platformMapping = "") override; - void WriteExternalProject(std::ostream& fout, const std::string& name, - const char* path, const char* typeGuid, - const std::set<BT<std::string>>& depends) override; + void WriteExternalProject( + std::ostream& fout, const std::string& name, const std::string& path, + const char* typeGuid, + const std::set<BT<std::pair<std::string, bool>>>& depends) override; // Folders are not supported by VS 7.1. bool UseFolderProperty() const override { return false; } diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 40b214c..43d31bc 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -2,8 +2,10 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio7Generator.h" +#include <utility> #include <vector> +#include <cm/memory> #include <cm/string_view> #include <windows.h> @@ -126,7 +128,7 @@ void cmGlobalVisualStudio7Generator::EnableLanguage( // does not know about. std::string extraPath; if (cmSystemTools::GetEnv("CMAKE_MSVCIDE_RUN_PATH", extraPath)) { - mf->AddCacheDefinition("CMAKE_MSVCIDE_RUN_PATH", extraPath.c_str(), + mf->AddCacheDefinition("CMAKE_MSVCIDE_RUN_PATH", extraPath, "Saved environment variable CMAKE_MSVCIDE_RUN_PATH", cmStateEnums::STATIC); } @@ -184,7 +186,7 @@ std::string cmGlobalVisualStudio7Generator::FindDevEnvCommand() } const char* cmGlobalVisualStudio7Generator::ExternalProjectType( - const char* location) + const std::string& location) { std::string extension = cmSystemTools::GetFilenameLastExtension(location); if (extension == ".vbproj") { @@ -263,12 +265,11 @@ cmGlobalVisualStudio7Generator::GenerateBuildCommand( } //! Create a local generator appropriate to this Global Generator -cmLocalGenerator* cmGlobalVisualStudio7Generator::CreateLocalGenerator( - cmMakefile* mf) +std::unique_ptr<cmLocalGenerator> +cmGlobalVisualStudio7Generator::CreateLocalGenerator(cmMakefile* mf) { - cmLocalVisualStudio7Generator* lg = - new cmLocalVisualStudio7Generator(this, mf); - return lg; + auto lg = cm::make_unique<cmLocalVisualStudio7Generator>(this, mf); + return std::unique_ptr<cmLocalGenerator>(std::move(lg)); } #if !defined(CMAKE_BOOTSTRAP) @@ -300,7 +301,7 @@ void cmGlobalVisualStudio7Generator::Generate() if (!cmSystemTools::GetErrorOccuredFlag() && !this->LocalGenerators.empty()) { this->CallVisualStudioMacro(MacroReload, - GetSLNFile(this->LocalGenerators[0])); + GetSLNFile(this->LocalGenerators[0].get())); } } @@ -345,8 +346,8 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations( if (expath) { std::set<std::string> allConfigurations(configs.begin(), configs.end()); const char* mapping = target->GetProperty("VS_PLATFORM_MAPPING"); - this->WriteProjectConfigurations(fout, target->GetName().c_str(), - *target, configs, allConfigurations, + this->WriteProjectConfigurations(fout, target->GetName(), *target, + configs, allConfigurations, mapping ? mapping : ""); } else { const std::set<std::string>& configsPartOfDefaultBuild = @@ -379,7 +380,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( std::string project = target->GetName(); std::string location = expath; - this->WriteExternalProject(fout, project.c_str(), location.c_str(), + this->WriteExternalProject(fout, project, location, target->GetProperty("VS_PROJECT_TYPE"), target->GetUtilities()); written = true; @@ -388,11 +389,11 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( if (vcprojName) { cmLocalGenerator* lg = target->GetLocalGenerator(); std::string dir = lg->GetCurrentBinaryDirectory(); - dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir.c_str()); + dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir); if (dir == ".") { dir.clear(); // msbuild cannot handle ".\" prefix } - this->WriteProject(fout, vcprojName, dir.c_str(), target); + this->WriteProject(fout, vcprojName, dir, target); written = true; } } @@ -482,7 +483,7 @@ void cmGlobalVisualStudio7Generator::WriteFoldersContent(std::ostream& fout) } std::string cmGlobalVisualStudio7Generator::ConvertToSolutionPath( - const char* path) + const std::string& path) { // Convert to backslashes. Do not use ConvertToOutputPath because // we will add quoting ourselves, and we know these projects always @@ -675,7 +676,8 @@ std::set<std::string> cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild( for (std::string const& i : configs) { const char* propertyValue = target->Target->GetMakefile()->GetDefinition(propertyName); - if (cmIsOn(cmGeneratorExpression::Evaluate( + if (propertyValue && + cmIsOn(cmGeneratorExpression::Evaluate( propertyValue, target->GetLocalGenerator(), i))) { activeConfigs.insert(i); } diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index 7a9fcef..6cc1cf8 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -3,6 +3,8 @@ #ifndef cmGlobalVisualStudio7Generator_h #define cmGlobalVisualStudio7Generator_h +#include <memory> + #include "cmGlobalGeneratorFactory.h" #include "cmGlobalVisualStudioGenerator.h" @@ -20,7 +22,8 @@ public: ~cmGlobalVisualStudio7Generator(); //! Create a local generator appropriate to this Global Generator - cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override; + std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( + cmMakefile* mf) override; #if !defined(CMAKE_BOOTSTRAP) Json::Value GetJson() const override; @@ -107,16 +110,17 @@ protected: std::string const& GetDevEnvCommand(); virtual std::string FindDevEnvCommand(); - static const char* ExternalProjectType(const char* location); + static const char* ExternalProjectType(const std::string& location); virtual void OutputSLNFile(cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators); virtual void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators) = 0; virtual void WriteProject(std::ostream& fout, const std::string& name, - const char* path, const cmGeneratorTarget* t) = 0; + const std::string& path, + const cmGeneratorTarget* t) = 0; virtual void WriteProjectDepends(std::ostream& fout, const std::string& name, - const char* path, + const std::string& path, cmGeneratorTarget const* t) = 0; virtual void WriteProjectConfigurations( std::ostream& fout, const std::string& name, @@ -138,10 +142,11 @@ protected: OrderedTargetDependSet const& projectTargets); virtual void WriteExternalProject( - std::ostream& fout, const std::string& name, const char* path, - const char* typeGuid, const std::set<BT<std::string>>& dependencies) = 0; + std::ostream& fout, const std::string& name, const std::string& path, + const char* typeGuid, + const std::set<BT<std::pair<std::string, bool>>>& dependencies) = 0; - std::string ConvertToSolutionPath(const char* path); + std::string ConvertToSolutionPath(const std::string& path); std::set<std::string> IsPartOfDefaultBuild( std::vector<std::string> const& configs, diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index 8e6125b..fa0e935 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -2,6 +2,9 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio8Generator.h" +#include <cm/memory> +#include <cmext/memory> + #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmDocumentationEntry.h" @@ -96,21 +99,22 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() return false; } - std::vector<cmLocalGenerator*> const& generators = this->LocalGenerators; - cmLocalVisualStudio7Generator* lg = - static_cast<cmLocalVisualStudio7Generator*>(generators[0]); - cmMakefile* mf = lg->GetMakefile(); + std::vector<std::unique_ptr<cmLocalGenerator>> const& generators = + this->LocalGenerators; + auto& lg = + cm::static_reference_cast<cmLocalVisualStudio7Generator>(generators[0]); const char* no_working_directory = nullptr; std::vector<std::string> no_byproducts; std::vector<std::string> no_depends; cmCustomCommandLines no_commands; - cmTarget* tgt = mf->AddUtilityCommand( - CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmCommandOrigin::Generator, false, - no_working_directory, no_byproducts, no_depends, no_commands); + cmTarget* tgt = lg.AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false, + no_working_directory, no_byproducts, + no_depends, no_commands); - cmGeneratorTarget* gt = new cmGeneratorTarget(tgt, lg); - lg->AddGeneratorTarget(gt); + auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, &lg); + auto gt = ptr.get(); + lg.AddGeneratorTarget(std::move(ptr)); // Organize in the "predefined targets" folder: // @@ -128,7 +132,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() stampList); std::string stampFile; cmGeneratedFileStream fout(stampListFile.c_str()); - for (cmLocalGenerator const* gi : generators) { + for (const auto& gi : generators) { stampFile = cmStrCat(gi->GetMakefile()->GetCurrentBinaryDirectory(), "/CMakeFiles/generate.stamp"); fout << stampFile << "\n"; @@ -141,8 +145,8 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() // Collect the input files used to generate all targets in this // project. std::vector<std::string> listFiles; - for (cmLocalGenerator* gen : generators) { - cmAppend(listFiles, gen->GetMakefile()->GetListFiles()); + for (const auto& gen : generators) { + cm::append(listFiles, gen->GetMakefile()->GetListFiles()); } // Add a custom prebuild target to run the VerifyGlobs script. @@ -153,7 +157,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() std::vector<std::string> byproducts; byproducts.push_back(cm->GetGlobVerifyStamp()); - mf->AddCustomCommandToTarget( + lg.AddCustomCommandToTarget( CMAKE_CHECK_BUILD_SYSTEM_TARGET, byproducts, no_depends, verifyCommandLines, cmCustomCommandType::PRE_BUILD, "Checking File Globs", no_working_directory, false); @@ -171,10 +175,10 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() listFiles.erase(new_end, listFiles.end()); // Create a rule to re-run CMake. - std::string argS = cmStrCat("-S", lg->GetSourceDirectory()); - std::string argB = cmStrCat("-B", lg->GetBinaryDirectory()); + std::string argS = cmStrCat("-S", lg.GetSourceDirectory()); + std::string argB = cmStrCat("-B", lg.GetBinaryDirectory()); std::string const sln = - lg->GetBinaryDirectory() + "/" + lg->GetProjectName() + ".sln"; + lg.GetBinaryDirectory() + "/" + lg.GetProjectName() + ".sln"; cmCustomCommandLines commandLines = cmMakeSingleCommandLine( { cmSystemTools::GetCMakeCommand(), argS, argB, "--check-stamp-list", stampList, "--vs-solution-file", sln }); @@ -185,7 +189,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() // (this could be avoided with per-target source files) std::string no_main_dependency; cmImplicitDependsList no_implicit_depends; - if (cmSourceFile* file = mf->AddCustomCommandToOutput( + if (cmSourceFile* file = lg.AddCustomCommandToOutput( stamps, no_byproducts, listFiles, no_main_dependency, no_implicit_depends, commandLines, "Checking Build System", no_working_directory, true, false)) { @@ -203,12 +207,11 @@ void cmGlobalVisualStudio8Generator::AddExtraIDETargets() cmGlobalVisualStudio7Generator::AddExtraIDETargets(); if (this->AddCheckTarget()) { for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) { - const std::vector<cmGeneratorTarget*>& tgts = - this->LocalGenerators[i]->GetGeneratorTargets(); + const auto& tgts = this->LocalGenerators[i]->GetGeneratorTargets(); // All targets depend on the build-system check target. - for (cmGeneratorTarget const* ti : tgts) { + for (const auto& ti : tgts) { if (ti->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { - ti->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET); + ti->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false); } } } @@ -272,23 +275,31 @@ void cmGlobalVisualStudio8Generator::WriteProjectConfigurations( bool cmGlobalVisualStudio8Generator::NeedsDeploy( cmGeneratorTarget const& target, const char* config) const { - cmStateEnums::TargetType type = target.GetType(); - bool noDeploy = DeployInhibited(target, config); - return !noDeploy && - (type == cmStateEnums::EXECUTABLE || - type == cmStateEnums::SHARED_LIBRARY) && - this->TargetSystemSupportsDeployment(); -} + cmStateEnums::TargetType const type = target.GetType(); + if (type != cmStateEnums::EXECUTABLE && + type != cmStateEnums::SHARED_LIBRARY) { + // deployment only valid on executables and shared libraries. + return false; + } -bool cmGlobalVisualStudio8Generator::DeployInhibited( - cmGeneratorTarget const& target, const char* config) const -{ - bool rVal = false; - if (const char* prop = target.GetProperty("VS_NO_SOLUTION_DEPLOY")) { - rVal = cmIsOn( + if (const char* prop = target.GetProperty("VS_SOLUTION_DEPLOY")) { + // If set, it dictates behavior + return cmIsOn( cmGeneratorExpression::Evaluate(prop, target.LocalGenerator, config)); } - return rVal; + + // To be deprecated, disable deployment even if target supports it. + if (const char* prop = target.GetProperty("VS_NO_SOLUTION_DEPLOY")) { + if (cmIsOn(cmGeneratorExpression::Evaluate(prop, target.LocalGenerator, + config))) { + // If true, always disable deployment + return false; + } + } + + // Legacy behavior, enabled deployment based on 'hard-coded' target + // platforms. + return this->TargetSystemSupportsDeployment(); } bool cmGlobalVisualStudio8Generator::TargetSystemSupportsDeployment() const @@ -304,7 +315,7 @@ bool cmGlobalVisualStudio8Generator::ComputeTargetDepends() } void cmGlobalVisualStudio8Generator::WriteProjectDepends( - std::ostream& fout, const std::string&, const char*, + std::ostream& fout, const std::string&, const std::string&, cmGeneratorTarget const* gt) { TargetDependSet const& unordered = this->GetTargetDirectDepends(gt); @@ -322,9 +333,10 @@ bool cmGlobalVisualStudio8Generator::NeedLinkLibraryDependencies( cmGeneratorTarget* target) { // Look for utility dependencies that magically link. - for (BT<std::string> const& ui : target->GetUtilities()) { + for (BT<std::pair<std::string, bool>> const& ui : target->GetUtilities()) { if (cmGeneratorTarget* depTarget = - target->GetLocalGenerator()->FindGeneratorTargetToUse(ui.Value)) { + target->GetLocalGenerator()->FindGeneratorTargetToUse( + ui.Value.first)) { if (depTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY && depTarget->GetProperty("EXTERNAL_MSPROJECT")) { // This utility dependency names an external .vcproj target. diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h index 352bc3c..6ce67d3 100644 --- a/Source/cmGlobalVisualStudio8Generator.h +++ b/Source/cmGlobalVisualStudio8Generator.h @@ -57,10 +57,6 @@ protected: virtual bool NeedsDeploy(cmGeneratorTarget const& target, const char* config) const; - /** Returns true if deployment has been disabled in cmake file. */ - bool DeployInhibited(cmGeneratorTarget const& target, - const char* config) const; - /** Returns true if the target system support debugging deployment. */ virtual bool TargetSystemSupportsDeployment() const; @@ -74,7 +70,7 @@ protected: const std::string& platformMapping = "") override; bool ComputeTargetDepends() override; void WriteProjectDepends(std::ostream& fout, const std::string& name, - const char* path, + const std::string& path, const cmGeneratorTarget* t) override; bool UseFolderProperty() const override; diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx index 6e61d26..9f73c15 100644 --- a/Source/cmGlobalVisualStudio9Generator.cxx +++ b/Source/cmGlobalVisualStudio9Generator.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio9Generator.h" +#include <utility> + #include "cmDocumentationEntry.h" #include "cmLocalVisualStudio7Generator.h" #include "cmMakefile.h" @@ -13,43 +15,46 @@ static const char vs9generatorName[] = "Visual Studio 9 2008"; class cmGlobalVisualStudio9Generator::Factory : public cmGlobalGeneratorFactory { public: - cmGlobalGenerator* CreateGlobalGenerator(const std::string& name, - cmake* cm) const override + std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( + const std::string& name, cmake* cm) const override { if (strncmp(name.c_str(), vs9generatorName, sizeof(vs9generatorName) - 1) != 0) { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } const char* p = name.c_str() + sizeof(vs9generatorName) - 1; if (p[0] == '\0') { - return new cmGlobalVisualStudio9Generator(cm, name, ""); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio9Generator(cm, name, "")); } if (p[0] != ' ') { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } ++p; if (!strcmp(p, "IA64")) { - return new cmGlobalVisualStudio9Generator(cm, name, "Itanium"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio9Generator(cm, name, "Itanium")); } if (!strcmp(p, "Win64")) { - return new cmGlobalVisualStudio9Generator(cm, name, "x64"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudio9Generator(cm, name, "x64")); } cmVisualStudioWCEPlatformParser parser(p); parser.ParseVersion("9.0"); if (!parser.Found()) { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } - cmGlobalVisualStudio9Generator* ret = - new cmGlobalVisualStudio9Generator(cm, name, p); + auto ret = std::unique_ptr<cmGlobalVisualStudio9Generator>( + new cmGlobalVisualStudio9Generator(cm, name, p)); ret->WindowsCEVersion = parser.GetOSVersion(); - return ret; + return std::unique_ptr<cmGlobalGenerator>(std::move(ret)); } void GetDocumentation(cmDocumentationEntry& entry) const override @@ -103,9 +108,10 @@ public: std::string GetDefaultPlatformName() const override { return "Win32"; } }; -cmGlobalGeneratorFactory* cmGlobalVisualStudio9Generator::NewFactory() +std::unique_ptr<cmGlobalGeneratorFactory> +cmGlobalVisualStudio9Generator::NewFactory() { - return new Factory; + return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory); } cmGlobalVisualStudio9Generator::cmGlobalVisualStudio9Generator( diff --git a/Source/cmGlobalVisualStudio9Generator.h b/Source/cmGlobalVisualStudio9Generator.h index 7bebfd6..53318a6 100644 --- a/Source/cmGlobalVisualStudio9Generator.h +++ b/Source/cmGlobalVisualStudio9Generator.h @@ -3,6 +3,8 @@ #ifndef cmGlobalVisualStudio9Generator_h #define cmGlobalVisualStudio9Generator_h +#include <memory> + #include "cmGlobalVisualStudio8Generator.h" /** \class cmGlobalVisualStudio9Generator @@ -13,7 +15,7 @@ class cmGlobalVisualStudio9Generator : public cmGlobalVisualStudio8Generator { public: - static cmGlobalGeneratorFactory* NewFactory(); + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory(); /** * Where does this version of Visual Studio look for macros for the diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index ed0cba7..1ec1559 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -7,6 +7,7 @@ #include <iostream> #include <cm/iterator> +#include <cm/memory> #include <windows.h> @@ -196,12 +197,12 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets() if (!gen.empty()) { // Use no actual command lines so that the target itself is not // considered always out of date. - cmTarget* allBuild = gen[0]->GetMakefile()->AddUtilityCommand( - "ALL_BUILD", cmCommandOrigin::Generator, true, no_working_dir, - no_byproducts, no_depends, no_commands, false, "Build all projects"); + cmTarget* allBuild = gen[0]->AddUtilityCommand( + "ALL_BUILD", true, no_working_dir, no_byproducts, no_depends, + no_commands, false, "Build all projects"); - cmGeneratorTarget* gt = new cmGeneratorTarget(allBuild, gen[0]); - gen[0]->AddGeneratorTarget(gt); + gen[0]->AddGeneratorTarget( + cm::make_unique<cmGeneratorTarget>(allBuild, gen[0])); // // Organize in the "predefined targets" folder: @@ -212,13 +213,13 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets() // Now make all targets depend on the ALL_BUILD target for (cmLocalGenerator const* i : gen) { - for (cmGeneratorTarget* tgt : i->GetGeneratorTargets()) { + for (const auto& tgt : i->GetGeneratorTargets()) { if (tgt->GetType() == cmStateEnums::GLOBAL_TARGET || tgt->IsImported()) { continue; } - if (!this->IsExcluded(gen[0], tgt)) { - allBuild->AddUtility(tgt->GetName()); + if (!this->IsExcluded(gen[0], tgt.get())) { + allBuild->AddUtility(tgt->GetName(), false); } } } @@ -307,7 +308,7 @@ void cmGlobalVisualStudioGenerator::CallVisualStudioMacro( if (!dir.empty()) { std::string macrosFile = dir + "/CMakeMacros/" CMAKE_VSMACROS_FILENAME; std::string nextSubkeyName; - if (cmSystemTools::FileExists(macrosFile.c_str()) && + if (cmSystemTools::FileExists(macrosFile) && IsVisualStudioMacrosFileRegistered( macrosFile, this->GetUserMacrosRegKeyBase(), nextSubkeyName)) { if (m == MacroReload) { @@ -389,8 +390,8 @@ bool cmGlobalVisualStudioGenerator::ComputeTargetDepends() } for (auto const& it : this->ProjectMap) { for (const cmLocalGenerator* i : it.second) { - for (cmGeneratorTarget* ti : i->GetGeneratorTargets()) { - this->ComputeVSTargetDepends(ti); + for (const auto& ti : i->GetGeneratorTargets()) { + this->ComputeVSTargetDepends(ti.get()); } } } @@ -592,7 +593,7 @@ bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile, std::string filepath; std::string filepathname; std::string filepathpath; - if (cmSystemTools::FileExists(fullname.c_str())) { + if (cmSystemTools::FileExists(fullname)) { filename = cmSystemTools::GetFilenameName(fullname); filepath = cmSystemTools::GetFilenamePath(fullname); filepathname = cmSystemTools::GetFilenameName(filepath); @@ -799,19 +800,9 @@ void RegisterVisualStudioMacros(const std::string& macrosFile, bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly( cmGeneratorTarget const* gt) { - // check to see if this is a fortran build - { - // Issue diagnostic if the source files depend on the config. - std::vector<cmSourceFile*> sources; - if (!gt->GetConfigCommonSourceFiles(sources)) { - return false; - } - } - // If there's only one source language, Fortran has to be used // in order for the sources to compile. - std::set<std::string> languages; - gt->GetLanguages(languages, ""); + std::set<std::string> languages = gt->GetAllConfigCompileLanguages(); // Consider an explicit linker language property, but *not* the // computed linker language that may depend on linked targets. // This allows the project to control the language choice in @@ -926,7 +917,7 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( std::string objFile = it; // replace $(ConfigurationName) in the object names cmSystemTools::ReplaceString(objFile, this->GetCMakeCFGIntDir(), - configName.c_str()); + configName); if (cmHasLiteralSuffix(objFile, ".obj")) { fout << objFile << "\n"; } @@ -939,9 +930,10 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( cmCustomCommandLines commandLines = cmMakeSingleCommandLine( { cmakeCommand, "-E", "__create_def", mdi->DefFile, objs_file }); - cmCustomCommand command(gt->Target->GetMakefile(), outputs, empty, empty, - commandLines, "Auto build dll exports", "."); - commands.push_back(command); + cmCustomCommand command(outputs, empty, empty, commandLines, + gt->Target->GetMakefile()->GetBacktrace(), + "Auto build dll exports", "."); + commands.push_back(std::move(command)); } static bool OpenSolution(std::string sln) diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 4f2007f..29a5c2c 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -150,6 +150,8 @@ public: bool Open(const std::string& bindir, const std::string& projectName, bool dryRun) override; + bool IsVisualStudio() const override { return true; } + protected: cmGlobalVisualStudioGenerator(cmake* cm, std::string const& platformInGeneratorName); diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index a371633..13ae32a 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -121,30 +121,33 @@ class cmGlobalVisualStudioVersionedGenerator::Factory15 : public cmGlobalGeneratorFactory { public: - cmGlobalGenerator* CreateGlobalGenerator(const std::string& name, - cmake* cm) const override + std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( + const std::string& name, cmake* cm) const override { std::string genName; const char* p = cmVS15GenName(name, genName); if (!p) { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } if (!*p) { - return new cmGlobalVisualStudioVersionedGenerator( - cmGlobalVisualStudioGenerator::VS15, cm, genName, ""); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudioVersionedGenerator( + cmGlobalVisualStudioGenerator::VS15, cm, genName, "")); } if (*p++ != ' ') { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } if (strcmp(p, "Win64") == 0) { - return new cmGlobalVisualStudioVersionedGenerator( - cmGlobalVisualStudioGenerator::VS15, cm, genName, "x64"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudioVersionedGenerator( + cmGlobalVisualStudioGenerator::VS15, cm, genName, "x64")); } if (strcmp(p, "ARM") == 0) { - return new cmGlobalVisualStudioVersionedGenerator( - cmGlobalVisualStudioGenerator::VS15, cm, genName, "ARM"); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudioVersionedGenerator( + cmGlobalVisualStudioGenerator::VS15, cm, genName, "ARM")); } - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } void GetDocumentation(cmDocumentationEntry& entry) const override @@ -185,10 +188,10 @@ public: std::string GetDefaultPlatformName() const override { return "Win32"; } }; -cmGlobalGeneratorFactory* +std::unique_ptr<cmGlobalGeneratorFactory> cmGlobalVisualStudioVersionedGenerator::NewFactory15() { - return new Factory15; + return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory15); } static const char vs16generatorName[] = "Visual Studio 16 2019"; @@ -212,19 +215,20 @@ class cmGlobalVisualStudioVersionedGenerator::Factory16 : public cmGlobalGeneratorFactory { public: - cmGlobalGenerator* CreateGlobalGenerator(const std::string& name, - cmake* cm) const override + std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( + const std::string& name, cmake* cm) const override { std::string genName; const char* p = cmVS16GenName(name, genName); if (!p) { - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } if (!*p) { - return new cmGlobalVisualStudioVersionedGenerator( - cmGlobalVisualStudioGenerator::VS16, cm, genName, ""); + return std::unique_ptr<cmGlobalGenerator>( + new cmGlobalVisualStudioVersionedGenerator( + cmGlobalVisualStudioGenerator::VS16, cm, genName, "")); } - return 0; + return std::unique_ptr<cmGlobalGenerator>(); } void GetDocumentation(cmDocumentationEntry& entry) const override @@ -265,10 +269,10 @@ public: } }; -cmGlobalGeneratorFactory* +std::unique_ptr<cmGlobalGeneratorFactory> cmGlobalVisualStudioVersionedGenerator::NewFactory16() { - return new Factory16; + return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory16); } cmGlobalVisualStudioVersionedGenerator::cmGlobalVisualStudioVersionedGenerator( diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h index 466816b..abb6095 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.h +++ b/Source/cmGlobalVisualStudioVersionedGenerator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <memory> #include <string> #include "cmGlobalVisualStudio14Generator.h" @@ -19,8 +20,8 @@ class cmGlobalVisualStudioVersionedGenerator : public cmGlobalVisualStudio14Generator { public: - static cmGlobalGeneratorFactory* NewFactory15(); - static cmGlobalGeneratorFactory* NewFactory16(); + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory15(); + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory16(); bool MatchesGeneratorName(const std::string& name) const override; diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h index 64ace13..c0daf8a 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.h +++ b/Source/cmGlobalWatcomWMakeGenerator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <memory> #include <string> #include <vector> @@ -25,9 +26,10 @@ class cmGlobalWatcomWMakeGenerator : public cmGlobalUnixMakefileGenerator3 { public: cmGlobalWatcomWMakeGenerator(cmake* cm); - static cmGlobalGeneratorFactory* NewFactory() + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory() { - return new cmGlobalGeneratorSimpleFactory<cmGlobalWatcomWMakeGenerator>(); + return std::unique_ptr<cmGlobalGeneratorFactory>( + new cmGlobalGeneratorSimpleFactory<cmGlobalWatcomWMakeGenerator>()); } //! Get the name for the generator. std::string GetName() const override diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index aee475b..9db4817 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2,13 +2,16 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalXCodeGenerator.h" +#include <algorithm> #include <cassert> #include <cstdio> #include <cstring> #include <iomanip> #include <sstream> +#include <utility> #include <cm/memory> +#include <cmext/algorithm> #include "cmsys/RegularExpression.hxx" @@ -129,8 +132,8 @@ public: class cmGlobalXCodeGenerator::Factory : public cmGlobalGeneratorFactory { public: - cmGlobalGenerator* CreateGlobalGenerator(const std::string& name, - cmake* cm) const override; + std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( + const std::string& name, cmake* cm) const override; void GetDocumentation(cmDocumentationEntry& entry) const override { @@ -179,16 +182,17 @@ cmGlobalXCodeGenerator::cmGlobalXCodeGenerator( cm->GetState()->SetIsGeneratorMultiConfig(true); } -cmGlobalGeneratorFactory* cmGlobalXCodeGenerator::NewFactory() +std::unique_ptr<cmGlobalGeneratorFactory> cmGlobalXCodeGenerator::NewFactory() { - return new Factory; + return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory); } -cmGlobalGenerator* cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator( - const std::string& name, cmake* cm) const +std::unique_ptr<cmGlobalGenerator> +cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator(const std::string& name, + cmake* cm) const { if (name != GetActualName()) { - return nullptr; + return std::unique_ptr<cmGlobalGenerator>(); } #if !defined(CMAKE_BOOTSTRAP) cmXcodeVersionParser parser; @@ -224,16 +228,17 @@ cmGlobalGenerator* cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator( if (version_number < 50) { cm->IssueMessage(MessageType::FATAL_ERROR, "Xcode " + version_string + " not supported."); - return nullptr; + return std::unique_ptr<cmGlobalGenerator>(); } - auto gg = cm::make_unique<cmGlobalXCodeGenerator>(cm, version_string, - version_number); - return gg.release(); + return std::unique_ptr<cmGlobalGenerator>( + cm::make_unique<cmGlobalXCodeGenerator>(cm, version_string, + version_number)); #else std::cerr << "CMake should be built with cmake to use Xcode, " "default to Xcode 1.5\n"; - return new cmGlobalXCodeGenerator(cm); + return std::unique_ptr<cmGlobalGenerator>( + cm::make_unique<cmGlobalXCodeGenerator>(cm)); #endif } @@ -267,7 +272,7 @@ std::string cmGlobalXCodeGenerator::FindXcodeBuildCommand() } bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts, - cmMakefile* mf) + bool build, cmMakefile* mf) { if (ts.find_first_of(",=") != std::string::npos) { std::ostringstream e; @@ -283,6 +288,9 @@ bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts, return false; } this->GeneratorToolset = ts; + if (build) { + return true; + } if (!this->GeneratorToolset.empty()) { mf->AddDefinition("CMAKE_XCODE_PLATFORM_TOOLSET", this->GeneratorToolset); } @@ -388,9 +396,11 @@ cmGlobalXCodeGenerator::GenerateBuildCommand( } //! Create a local generator appropriate to this Global Generator -cmLocalGenerator* cmGlobalXCodeGenerator::CreateLocalGenerator(cmMakefile* mf) +std::unique_ptr<cmLocalGenerator> cmGlobalXCodeGenerator::CreateLocalGenerator( + cmMakefile* mf) { - return new cmLocalXCodeGenerator(this, mf); + return std::unique_ptr<cmLocalGenerator>( + cm::make_unique<cmLocalXCodeGenerator>(this, mf)); } void cmGlobalXCodeGenerator::AddExtraIDETargets() @@ -409,10 +419,10 @@ void cmGlobalXCodeGenerator::ComputeTargetOrder() { size_t index = 0; auto const& lgens = this->GetLocalGenerators(); - for (cmLocalGenerator* lgen : lgens) { - auto const& targets = lgen->GetGeneratorTargets(); - for (cmGeneratorTarget const* gt : targets) { - this->ComputeTargetOrder(gt, index); + for (auto const& lgen : lgens) { + const auto& targets = lgen->GetGeneratorTargets(); + for (const auto& gt : targets) { + this->ComputeTargetOrder(gt.get(), index); } } assert(index == this->TargetOrderIndex.size()); @@ -496,20 +506,16 @@ std::string cmGlobalXCodeGenerator::PostBuildMakeTarget( void cmGlobalXCodeGenerator::AddExtraTargets( cmLocalGenerator* root, std::vector<cmLocalGenerator*>& gens) { - cmMakefile* mf = root->GetMakefile(); - const char* no_working_directory = nullptr; std::vector<std::string> no_byproducts; std::vector<std::string> no_depends; // Add ALL_BUILD - cmTarget* allbuild = mf->AddUtilityCommand( - "ALL_BUILD", cmCommandOrigin::Generator, true, no_working_directory, - no_byproducts, no_depends, + cmTarget* allbuild = root->AddUtilityCommand( + "ALL_BUILD", true, no_working_directory, no_byproducts, no_depends, cmMakeSingleCommandLine({ "echo", "Build all projects" })); - cmGeneratorTarget* allBuildGt = new cmGeneratorTarget(allbuild, root); - root->AddGeneratorTarget(allBuildGt); + root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(allbuild, root)); // Add XCODE depend helper std::string dir = root->GetCurrentBinaryDirectory(); @@ -520,52 +526,53 @@ void cmGlobalXCodeGenerator::AddExtraTargets( // Add ZERO_CHECK bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION"); bool generateTopLevelProjectOnly = - mf->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY"); + root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY"); bool isTopLevel = !root->GetStateSnapshot().GetBuildsystemDirectoryParent().IsValid(); - if (regenerate && (isTopLevel || !generateTopLevelProjectOnly)) { + bool isGenerateProject = isTopLevel || !generateTopLevelProjectOnly; + if (regenerate && isGenerateProject) { this->CreateReRunCMakeFile(root, gens); std::string file = this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile); cmSystemTools::ReplaceString(file, "\\ ", " "); - cmTarget* check = mf->AddUtilityCommand( - CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmCommandOrigin::Generator, true, - no_working_directory, no_byproducts, no_depends, - cmMakeSingleCommandLine({ "make", "-f", file })); + cmTarget* check = + root->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, true, + no_working_directory, no_byproducts, no_depends, + cmMakeSingleCommandLine({ "make", "-f", file })); - cmGeneratorTarget* checkGt = new cmGeneratorTarget(check, root); - root->AddGeneratorTarget(checkGt); + root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(check, root)); } // now make the allbuild depend on all the non-utility targets // in the project for (auto& gen : gens) { - for (auto target : gen->GetGeneratorTargets()) { + for (const auto& target : gen->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::GLOBAL_TARGET) { continue; } if (regenerate && (target->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET)) { - target->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET); + target->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false); } // make all exe, shared libs and modules // run the depend check makefile as a post build rule // this will make sure that when the next target is built // things are up-to-date - if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { + if (isGenerateProject && + target->GetType() == cmStateEnums::OBJECT_LIBRARY) { commandLines.front().back() = // fill placeholder this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)"); - gen->GetMakefile()->AddCustomCommandToTarget( + gen->AddCustomCommandToTarget( target->GetName(), no_byproducts, no_depends, commandLines, cmCustomCommandType::POST_BUILD, "Depend check for xcode", dir.c_str(), true, false, "", "", false, cmObjectLibraryCommands::Accept); } - if (!this->IsExcluded(gens[0], target)) { - allbuild->AddUtility(target->GetName()); + if (!this->IsExcluded(gens[0], target.get())) { + allbuild->AddUtility(target->GetName(), false); } } } @@ -576,7 +583,7 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile( { std::vector<std::string> lfiles; for (auto gen : gens) { - cmAppend(lfiles, gen->GetMakefile()->GetListFiles()); + cm::append(lfiles, gen->GetMakefile()->GetListFiles()); } // sort the array @@ -636,7 +643,8 @@ void cmGlobalXCodeGenerator::CreateReRunCMakeFile( << "\n"; } -static bool objectIdLessThan(cmXCodeObject* l, cmXCodeObject* r) +static bool objectIdLessThan(const std::unique_ptr<cmXCodeObject>& l, + const std::unique_ptr<cmXCodeObject>& r) { return l->GetId() < r->GetId(); } @@ -650,9 +658,6 @@ void cmGlobalXCodeGenerator::SortXCodeObjects() void cmGlobalXCodeGenerator::ClearXCodeObjects() { this->TargetDoneSet.clear(); - for (auto& obj : this->XCodeObjects) { - delete obj; - } this->XCodeObjects.clear(); this->XCodeObjectIDs.clear(); this->XCodeObjectMap.clear(); @@ -662,7 +667,7 @@ void cmGlobalXCodeGenerator::ClearXCodeObjects() this->FileRefs.clear(); } -void cmGlobalXCodeGenerator::addObject(cmXCodeObject* obj) +void cmGlobalXCodeGenerator::addObject(std::unique_ptr<cmXCodeObject> obj) { if (obj->GetType() == cmXCodeObject::OBJECT) { const std::string& id = obj->GetId(); @@ -677,22 +682,24 @@ void cmGlobalXCodeGenerator::addObject(cmXCodeObject* obj) this->XCodeObjectIDs.insert(id); } - this->XCodeObjects.push_back(obj); + this->XCodeObjects.push_back(std::move(obj)); } cmXCodeObject* cmGlobalXCodeGenerator::CreateObject( cmXCodeObject::PBXType ptype) { - cmXCodeObject* obj = new cmXCode21Object(ptype, cmXCodeObject::OBJECT); - this->addObject(obj); - return obj; + auto obj = cm::make_unique<cmXCode21Object>(ptype, cmXCodeObject::OBJECT); + auto ptr = obj.get(); + this->addObject(std::move(obj)); + return ptr; } cmXCodeObject* cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type) { - cmXCodeObject* obj = new cmXCodeObject(cmXCodeObject::None, type); - this->addObject(obj); - return obj; + auto obj = cm::make_unique<cmXCodeObject>(cmXCodeObject::None, type); + auto ptr = obj.get(); + this->addObject(std::move(obj)); + return ptr; } cmXCodeObject* cmGlobalXCodeGenerator::CreateString(const std::string& s) @@ -1093,8 +1100,8 @@ bool cmGlobalXCodeGenerator::CreateXCodeTargets( cmLocalGenerator* gen, std::vector<cmXCodeObject*>& targets) { this->SetCurrentLocalGenerator(gen); - std::vector<cmGeneratorTarget*> gts = - this->CurrentLocalGenerator->GetGeneratorTargets(); + std::vector<cmGeneratorTarget*> gts; + cm::append(gts, this->CurrentLocalGenerator->GetGeneratorTargets()); std::sort(gts.begin(), gts.end(), [this](cmGeneratorTarget const* l, cmGeneratorTarget const* r) { return this->TargetOrderIndex[l] < this->TargetOrderIndex[r]; @@ -1364,11 +1371,11 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( void cmGlobalXCodeGenerator::ForceLinkerLanguages() { - for (auto localGenerator : this->LocalGenerators) { + for (const auto& localGenerator : this->LocalGenerators) { // All targets depend on the build-system check target. - for (auto tgt : localGenerator->GetGeneratorTargets()) { + for (const auto& tgt : localGenerator->GetGeneratorTargets()) { // This makes sure all targets link using the proper language. - this->ForceLinkerLanguage(tgt); + this->ForceLinkerLanguage(tgt.get()); } } } @@ -1460,12 +1467,12 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library", str_file, str_so_file, str_link_file }); - cmCustomCommand command(this->CurrentMakefile, std::vector<std::string>(), - std::vector<std::string>(), - std::vector<std::string>(), cmd, - "Creating symlinks", ""); + cmCustomCommand command( + std::vector<std::string>(), std::vector<std::string>(), + std::vector<std::string>(), cmd, this->CurrentMakefile->GetBacktrace(), + "Creating symlinks", ""); - postbuild.push_back(command); + postbuild.push_back(std::move(command)); } std::vector<cmSourceFile*> classes; @@ -2353,9 +2360,6 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, buildSettings->AddAttribute("SECTORDER_FLAGS", this->CreateString("")); buildSettings->AddAttribute("USE_HEADERMAP", this->CreateString("NO")); cmXCodeObject* group = this->CreateObject(cmXCodeObject::OBJECT_LIST); - group->AddObject(this->CreateString("-Wmost")); - group->AddObject(this->CreateString("-Wno-four-char-constants")); - group->AddObject(this->CreateString("-Wno-unknown-pragmas")); group->AddObject(this->CreateString("$(inherited)")); buildSettings->AddAttribute("WARNING_CFLAGS", group); @@ -2365,8 +2369,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, int minor; int patch; - // VERSION -> current_version - gtgt->GetTargetVersion(false, major, minor, patch); + // MACHO_CURRENT_VERSION or VERSION -> current_version + gtgt->GetTargetVersionFallback("MACHO_CURRENT_VERSION", "VERSION", major, + minor, patch); std::ostringstream v; // Xcode always wants at least 1.0.0 or nothing @@ -2376,8 +2381,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, buildSettings->AddAttribute("DYLIB_CURRENT_VERSION", this->CreateString(v.str())); - // SOVERSION -> compatibility_version - gtgt->GetTargetVersion(true, major, minor, patch); + // MACHO_COMPATIBILITY_VERSION or SOVERSION -> compatibility_version + gtgt->GetTargetVersionFallback("MACHO_COMPATIBILITY_VERSION", "SOVERSION", + major, minor, patch); std::ostringstream vso; // Xcode always wants at least 1.0.0 or nothing @@ -2405,8 +2411,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, std::string attribute = prop.substr(16); this->FilterConfigurationAttribute(configName, attribute); if (!attribute.empty()) { + const char* pr = gtgt->GetProperty(prop); std::string processed = cmGeneratorExpression::Evaluate( - gtgt->GetProperty(prop), this->CurrentLocalGenerator, configName); + pr ? pr : "", this->CurrentLocalGenerator, configName); buildSettings->AddAttribute(attribute, this->CreateString(processed)); } @@ -2834,7 +2841,7 @@ bool cmGlobalXCodeGenerator::CreateGroups( for (auto& generator : generators) { cmMakefile* mf = generator->GetMakefile(); std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups(); - for (auto gtgt : generator->GetGeneratorTargets()) { + for (const auto& gtgt : generator->GetGeneratorTargets()) { // Same skipping logic here as in CreateXCodeTargets so that we do not // end up with (empty anyhow) ZERO_CHECK, install, or test source // groups: @@ -2849,11 +2856,12 @@ bool cmGlobalXCodeGenerator::CreateGroups( continue; } - auto addSourceToGroup = [this, mf, gtgt, + auto addSourceToGroup = [this, mf, >gt, &sourceGroups](std::string const& source) { cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups); - cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup); - std::string key = GetGroupMapKeyFromPath(gtgt, source); + cmXCodeObject* pbxgroup = + this->CreateOrGetPBXGroup(gtgt.get(), sourceGroup); + std::string key = GetGroupMapKeyFromPath(gtgt.get(), source); this->GroupMap[key] = pbxgroup; }; @@ -2879,7 +2887,7 @@ bool cmGlobalXCodeGenerator::CreateGroups( // Add the Info.plist we are about to generate for an App Bundle. if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) { - std::string plist = this->ComputeInfoPListLocation(gtgt); + std::string plist = this->ComputeInfoPListLocation(gtgt.get()); cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource( plist, true, cmSourceFileLocationKind::Known); addSourceToGroup(sf->ResolveFullPath()); @@ -3140,7 +3148,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( this->FilterConfigurationAttribute(config.first, attribute); if (!attribute.empty()) { std::string processed = cmGeneratorExpression::Evaluate( - this->CurrentMakefile->GetDefinition(var), + this->CurrentMakefile->GetSafeDefinition(var), this->CurrentLocalGenerator, config.first); buildSettingsForCfg->AddAttribute(attribute, this->CreateString(processed)); @@ -3384,7 +3392,7 @@ bool cmGlobalXCodeGenerator::OutputXCodeSharedSchemes( // collect all tests for the targets std::map<std::string, cmXCodeScheme::TestObjects> testables; - for (auto obj : this->XCodeObjects) { + for (const auto& obj : this->XCodeObjects) { if (obj->GetType() != cmXCodeObject::OBJECT || obj->GetIsA() != cmXCodeObject::PBXNativeTarget) { continue; @@ -3399,7 +3407,7 @@ bool cmGlobalXCodeGenerator::OutputXCodeSharedSchemes( continue; } - testables[testee].push_back(obj); + testables[testee].push_back(obj.get()); } // generate scheme @@ -3408,14 +3416,14 @@ bool cmGlobalXCodeGenerator::OutputXCodeSharedSchemes( // Since the lowest available Xcode version for testing was 6.4, // I'm setting this as a limit then if (this->XcodeVersion >= 64) { - for (auto obj : this->XCodeObjects) { + for (const auto& obj : this->XCodeObjects) { if (obj->GetType() == cmXCodeObject::OBJECT && (obj->GetIsA() == cmXCodeObject::PBXNativeTarget || obj->GetIsA() == cmXCodeObject::PBXAggregateTarget) && (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() || obj->GetTarget()->GetPropertyAsBool("XCODE_GENERATE_SCHEME"))) { const std::string& targetName = obj->GetTarget()->GetName(); - cmXCodeScheme schm(obj, testables[targetName], + cmXCodeScheme schm(root, obj.get(), testables[targetName], this->CurrentConfigurationTypes, this->XcodeVersion); schm.WriteXCodeSharedScheme(xcProjDir, diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index af905d0..e380f1c 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -7,6 +7,7 @@ #include <iosfwd> #include <map> +#include <memory> #include <set> #include <string> #include <vector> @@ -34,7 +35,11 @@ class cmGlobalXCodeGenerator : public cmGlobalGenerator public: cmGlobalXCodeGenerator(cmake* cm, std::string const& version_string, unsigned int version_number); - static cmGlobalGeneratorFactory* NewFactory(); + static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory(); + + cmGlobalXCodeGenerator(const cmGlobalXCodeGenerator&) = delete; + const cmGlobalXCodeGenerator& operator=(const cmGlobalXCodeGenerator&) = + delete; //! Get the name for the generator. std::string GetName() const override @@ -47,7 +52,8 @@ public: static void GetDocumentation(cmDocumentationEntry& entry); //! Create a local generator appropriate to this Global Generator - cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override; + std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( + cmMakefile* mf) override; /** * Try to determine system information such as shared library @@ -103,7 +109,8 @@ public: bool ShouldStripResourcePath(cmMakefile*) const override; - bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override; + bool SetGeneratorToolset(std::string const& ts, bool build, + cmMakefile* mf) override; void AppendFlag(std::string& flags, std::string const& flag) const; protected: @@ -246,7 +253,7 @@ protected: unsigned int XcodeVersion; std::string VersionString; std::set<std::string> XCodeObjectIDs; - std::vector<cmXCodeObject*> XCodeObjects; + std::vector<std::unique_ptr<cmXCodeObject>> XCodeObjects; cmXCodeObject* RootObject; private: @@ -270,7 +277,7 @@ private: void ComputeArchitectures(cmMakefile* mf); void ComputeObjectDirArch(cmMakefile* mf); - void addObject(cmXCodeObject* obj); + void addObject(std::unique_ptr<cmXCodeObject> obj); std::string PostBuildMakeTarget(std::string const& tName, std::string const& configName); cmXCodeObject* MainGroupChildren; diff --git a/Source/cmGraphAdjacencyList.h b/Source/cmGraphAdjacencyList.h index 5ed6af4..4e1f128 100644 --- a/Source/cmGraphAdjacencyList.h +++ b/Source/cmGraphAdjacencyList.h @@ -18,9 +18,10 @@ class cmGraphEdge { public: - cmGraphEdge(int n, bool s, cmListFileBacktrace bt) + cmGraphEdge(int n, bool s, bool c, cmListFileBacktrace bt) : Dest(n) , Strong(s) + , Cross(c) , Backtrace(std::move(bt)) { } @@ -28,11 +29,14 @@ public: bool IsStrong() const { return this->Strong; } + bool IsCross() const { return this->Cross; } + cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; } private: int Dest; bool Strong; + bool Cross; cmListFileBacktrace Backtrace; }; struct cmGraphEdgeList : public std::vector<cmGraphEdge> diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx index e0d545d..1b77678 100644 --- a/Source/cmGraphVizWriter.cxx +++ b/Source/cmGraphVizWriter.cxx @@ -2,174 +2,190 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGraphVizWriter.h" -#include <cstddef> +#include <cctype> #include <iostream> #include <memory> -#include <sstream> +#include <set> #include <utility> +#include <cm/memory> + #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmLinkItem.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include "cmTarget.h" #include "cmake.h" namespace { -enum LinkLibraryScopeType -{ - LLT_SCOPE_PUBLIC, - LLT_SCOPE_PRIVATE, - LLT_SCOPE_INTERFACE -}; -const char* const GRAPHVIZ_PRIVATE_EDEGE_STYLE = "dashed"; -const char* const GRAPHVIZ_INTERFACE_EDEGE_STYLE = "dotted"; +char const* const GRAPHVIZ_EDGE_STYLE_PUBLIC = "solid"; +char const* const GRAPHVIZ_EDGE_STYLE_INTERFACE = "dashed"; +char const* const GRAPHVIZ_EDGE_STYLE_PRIVATE = "dotted"; -std::string getLinkLibraryStyle(const LinkLibraryScopeType& type) -{ - std::string style; - switch (type) { - case LLT_SCOPE_PRIVATE: - style = "[style = " + std::string(GRAPHVIZ_PRIVATE_EDEGE_STYLE) + "]"; - break; - case LLT_SCOPE_INTERFACE: - style = "[style = " + std::string(GRAPHVIZ_INTERFACE_EDEGE_STYLE) + "]"; - break; - default: - break; - } - return style; -} +char const* const GRAPHVIZ_NODE_SHAPE_EXECUTABLE = "egg"; // egg-xecutable + +// Normal libraries. +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC = "octagon"; +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED = "doubleoctagon"; +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE = "tripleoctagon"; -const char* getShapeForTarget(const cmGeneratorTarget* target) +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE = "pentagon"; +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT = "hexagon"; +char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN = "septagon"; + +char const* const GRAPHVIZ_NODE_SHAPE_UTILITY = "box"; + +const char* getShapeForTarget(const cmLinkItem& item) { - if (!target) { - return "ellipse"; + if (item.Target == nullptr) { + return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN; } - switch (target->GetType()) { + switch (item.Target->GetType()) { case cmStateEnums::EXECUTABLE: - return "house"; + return GRAPHVIZ_NODE_SHAPE_EXECUTABLE; case cmStateEnums::STATIC_LIBRARY: - return "diamond"; + return GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC; case cmStateEnums::SHARED_LIBRARY: - return "polygon"; + return GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED; case cmStateEnums::MODULE_LIBRARY: - return "octagon"; + return GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE; + case cmStateEnums::OBJECT_LIBRARY: + return GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT; + case cmStateEnums::UTILITY: + return GRAPHVIZ_NODE_SHAPE_UTILITY; + case cmStateEnums::INTERFACE_LIBRARY: + return GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE; + case cmStateEnums::UNKNOWN_LIBRARY: default: - break; + return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN; } +} +} - return "box"; +cmGraphVizWriter::cmGraphVizWriter(std::string const& fileName, + const cmGlobalGenerator* globalGenerator) + : FileName(fileName) + , GlobalFileStream(fileName) + , GraphName(globalGenerator->GetSafeGlobalSetting("CMAKE_PROJECT_NAME")) + , GraphHeader("node [\n fontsize = \"12\"\n];") + , GraphNodePrefix("node") + , GlobalGenerator(globalGenerator) + , NextNodeId(0) + , GenerateForExecutables(true) + , GenerateForStaticLibs(true) + , GenerateForSharedLibs(true) + , GenerateForModuleLibs(true) + , GenerateForInterfaceLibs(true) + , GenerateForObjectLibs(true) + , GenerateForUnknownLibs(true) + , GenerateForCustomTargets(false) + , GenerateForExternals(true) + , GeneratePerTarget(true) + , GenerateDependers(true) +{ } -std::map<std::string, LinkLibraryScopeType> getScopedLinkLibrariesFromTarget( - cmTarget* Target, const cmGlobalGenerator* globalGenerator) +cmGraphVizWriter::~cmGraphVizWriter() { - char sep = ';'; - std::map<std::string, LinkLibraryScopeType> tokens; - size_t start = 0; - size_t end = 0; + this->WriteFooter(this->GlobalFileStream); - const char* pInterfaceLinkLibraries = - Target->GetProperty("INTERFACE_LINK_LIBRARIES"); - const char* pLinkLibraries = Target->GetProperty("LINK_LIBRARIES"); + for (auto& fileStream : this->PerTargetFileStreams) { + this->WriteFooter(*fileStream.second); + } - if (!pInterfaceLinkLibraries && !pLinkLibraries) { - return tokens; // target is not linked against any other libraries + for (auto& fileStream : this->TargetDependersFileStreams) { + this->WriteFooter(*fileStream.second); } +} - // make sure we don't touch a null-ptr - auto interfaceLinkLibraries = - std::string(pInterfaceLinkLibraries ? pInterfaceLinkLibraries : ""); - auto linkLibraries = std::string(pLinkLibraries ? pLinkLibraries : ""); +void cmGraphVizWriter::VisitGraph(std::string const&) +{ + this->WriteHeader(GlobalFileStream, this->GraphName); + this->WriteLegend(GlobalFileStream); +} - // first extract interfaceLinkLibraries - while (start < interfaceLinkLibraries.length()) { +void cmGraphVizWriter::OnItem(cmLinkItem const& item) +{ + if (this->ItemExcluded(item)) { + return; + } - if ((end = interfaceLinkLibraries.find(sep, start)) == std::string::npos) { - end = interfaceLinkLibraries.length(); - } + NodeNames[item.AsStr()] = cmStrCat(GraphNodePrefix, NextNodeId); + ++NextNodeId; - std::string element = interfaceLinkLibraries.substr(start, end - start); - if (globalGenerator->IsAlias(element)) { - const auto tgt = globalGenerator->FindTarget(element); - if (tgt) { - element = tgt->GetName(); - } - } + this->WriteNode(this->GlobalFileStream, item); - if (std::string::npos == element.find("$<LINK_ONLY:", 0)) { - // we assume first, that this library is an interface library. - // if we find it again in the linklibraries property, we promote it to an - // public library. - tokens[element] = LLT_SCOPE_INTERFACE; - } else { - // this is an private linked static library. - // we take care of this case in the second iterator. - } - start = end + 1; + if (this->GeneratePerTarget) { + this->CreateTargetFile(this->PerTargetFileStreams, item); } - // second extract linkLibraries - start = 0; - while (start < linkLibraries.length()) { - - if ((end = linkLibraries.find(sep, start)) == std::string::npos) { - end = linkLibraries.length(); - } + if (this->GenerateDependers) { + this->CreateTargetFile(this->TargetDependersFileStreams, item, + ".dependers"); + } +} - std::string element = linkLibraries.substr(start, end - start); - if (globalGenerator->IsAlias(element)) { - const auto tgt = globalGenerator->FindTarget(element); - if (tgt) { - element = tgt->GetName(); - } - } +void cmGraphVizWriter::CreateTargetFile(FileStreamMap& fileStreamMap, + cmLinkItem const& item, + std::string const& fileNameSuffix) +{ + auto const pathSafeItemName = PathSafeString(item.AsStr()); + auto const perTargetFileName = + cmStrCat(this->FileName, '.', pathSafeItemName, fileNameSuffix); + auto perTargetFileStream = + cm::make_unique<cmGeneratedFileStream>(perTargetFileName); - if (tokens.find(element) == tokens.end()) { - // this library is not found in interfaceLinkLibraries but in - // linkLibraries. - // this results in a private linked library. - tokens[element] = LLT_SCOPE_PRIVATE; - } else if (LLT_SCOPE_INTERFACE == tokens[element]) { - // this library is found in interfaceLinkLibraries and linkLibraries. - // this results in a public linked library. - tokens[element] = LLT_SCOPE_PUBLIC; - } else { - // private and public linked libraries should not be changed anymore. - } + this->WriteHeader(*perTargetFileStream, item.AsStr()); + this->WriteNode(*perTargetFileStream, item); - start = end + 1; - } + fileStreamMap.emplace(item.AsStr(), std::move(perTargetFileStream)); +} - return tokens; +void cmGraphVizWriter::OnDirectLink(cmLinkItem const& depender, + cmLinkItem const& dependee, + DependencyType dt) +{ + this->VisitLink(depender, dependee, true, GetEdgeStyle(dt)); } + +void cmGraphVizWriter::OnIndirectLink(cmLinkItem const& depender, + cmLinkItem const& dependee) +{ + this->VisitLink(depender, dependee, false); } -cmGraphVizWriter::cmGraphVizWriter(const cmGlobalGenerator* globalGenerator) - : GraphType("digraph") - , GraphName("GG") - , GraphHeader("node [\n fontsize = \"12\"\n];") - , GraphNodePrefix("node") - , GlobalGenerator(globalGenerator) - , LocalGenerators(globalGenerator->GetLocalGenerators()) - , GenerateForExecutables(true) - , GenerateForStaticLibs(true) - , GenerateForSharedLibs(true) - , GenerateForModuleLibs(true) - , GenerateForInterface(true) - , GenerateForExternals(true) - , GeneratePerTarget(true) - , GenerateDependers(true) - , HaveTargetsAndLibs(false) +void cmGraphVizWriter::VisitLink(cmLinkItem const& depender, + cmLinkItem const& dependee, bool isDirectLink, + std::string const& scopeType) { + if (this->ItemExcluded(depender) || this->ItemExcluded(dependee)) { + return; + } + + if (!isDirectLink) { + return; + } + + this->WriteConnection(this->GlobalFileStream, depender, dependee, scopeType); + + if (this->GeneratePerTarget) { + auto fileStream = PerTargetFileStreams[depender.AsStr()].get(); + this->WriteNode(*fileStream, dependee); + this->WriteConnection(*fileStream, depender, dependee, scopeType); + } + + if (this->GenerateDependers) { + auto fileStream = TargetDependersFileStreams[dependee.AsStr()].get(); + this->WriteNode(*fileStream, depender); + this->WriteConnection(*fileStream, depender, dependee, scopeType); + } } void cmGraphVizWriter::ReadSettings( @@ -208,7 +224,6 @@ void cmGraphVizWriter::ReadSettings( } \ } while (false) - __set_if_set(this->GraphType, "GRAPHVIZ_GRAPH_TYPE"); __set_if_set(this->GraphName, "GRAPHVIZ_GRAPH_NAME"); __set_if_set(this->GraphHeader, "GRAPHVIZ_GRAPH_HEADER"); __set_if_set(this->GraphNodePrefix, "GRAPHVIZ_NODE_PREFIX"); @@ -225,7 +240,10 @@ void cmGraphVizWriter::ReadSettings( __set_bool_if_set(this->GenerateForStaticLibs, "GRAPHVIZ_STATIC_LIBS"); __set_bool_if_set(this->GenerateForSharedLibs, "GRAPHVIZ_SHARED_LIBS"); __set_bool_if_set(this->GenerateForModuleLibs, "GRAPHVIZ_MODULE_LIBS"); - __set_bool_if_set(this->GenerateForInterface, "GRAPHVIZ_INTERFACE"); + __set_bool_if_set(this->GenerateForInterfaceLibs, "GRAPHVIZ_INTERFACE_LIBS"); + __set_bool_if_set(this->GenerateForObjectLibs, "GRAPHVIZ_OBJECT_LIBS"); + __set_bool_if_set(this->GenerateForUnknownLibs, "GRAPHVIZ_UNKNOWN_LIBS"); + __set_bool_if_set(this->GenerateForCustomTargets, "GRAPHVIZ_CUSTOM_TARGETS"); __set_bool_if_set(this->GenerateForExternals, "GRAPHVIZ_EXTERNAL_LIBS"); __set_bool_if_set(this->GeneratePerTarget, "GRAPHVIZ_GENERATE_PER_TARGET"); __set_bool_if_set(this->GenerateDependers, "GRAPHVIZ_GENERATE_DEPENDERS"); @@ -248,329 +266,170 @@ void cmGraphVizWriter::ReadSettings( } } -// Iterate over all targets and write for each one a graph which shows -// which other targets depend on it. -void cmGraphVizWriter::WriteTargetDependersFiles(const std::string& fileName) +void cmGraphVizWriter::Write() { - if (!this->GenerateDependers) { - return; - } - - this->CollectTargetsAndLibs(); - - for (auto const& ptr : this->TargetPtrs) { - if (ptr.second == nullptr) { - continue; - } - - if (!this->GenerateForTargetType(ptr.second->GetType())) { - continue; - } - - std::string currentFilename = - cmStrCat(fileName, '.', ptr.first, ".dependers"); - - cmGeneratedFileStream str(currentFilename); - if (!str) { - return; + auto gg = this->GlobalGenerator; + + this->VisitGraph(gg->GetName()); + + // We want to traverse in a determined order, such that the output is always + // the same for a given project (this makes tests reproducible, etc.) + std::set<cmGeneratorTarget const*, cmGeneratorTarget::StrictTargetComparison> + sortedGeneratorTargets; + + for (const auto& lg : gg->GetLocalGenerators()) { + for (const auto& gt : lg->GetGeneratorTargets()) { + // Reserved targets have inconsistent names across platforms (e.g. 'all' + // vs. 'ALL_BUILD'), which can disrupt the traversal ordering. + // We don't need or want them anyway. + if (!cmGlobalGenerator::IsReservedTarget(gt->GetName())) { + sortedGeneratorTargets.insert(gt.get()); + } } - - std::set<std::string> insertedConnections; - std::set<std::string> insertedNodes; - - std::cout << "Writing " << currentFilename << "..." << std::endl; - this->WriteHeader(str); - - this->WriteDependerConnections(ptr.first, insertedNodes, - insertedConnections, str); - - this->WriteFooter(str); - } -} - -// Iterate over all targets and write for each one a graph which shows -// on which targets it depends. -void cmGraphVizWriter::WritePerTargetFiles(const std::string& fileName) -{ - if (!this->GeneratePerTarget) { - return; } - this->CollectTargetsAndLibs(); - - for (auto const& ptr : this->TargetPtrs) { - if (ptr.second == nullptr) { - continue; - } - - if (!this->GenerateForTargetType(ptr.second->GetType())) { - continue; - } - - std::set<std::string> insertedConnections; - std::set<std::string> insertedNodes; - - std::string currentFilename = cmStrCat(fileName, '.', ptr.first); - cmGeneratedFileStream str(currentFilename); - if (!str) { - return; - } - - std::cout << "Writing " << currentFilename << "..." << std::endl; - this->WriteHeader(str); - - this->WriteConnections(ptr.first, insertedNodes, insertedConnections, str); - this->WriteFooter(str); + for (auto const gt : sortedGeneratorTargets) { + auto item = cmLinkItem(gt, false, gt->GetBacktrace()); + this->VisitItem(item); } } -void cmGraphVizWriter::WriteGlobalFile(const std::string& fileName) +void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& fs, + const std::string& name) { - this->CollectTargetsAndLibs(); - - cmGeneratedFileStream str(fileName); - if (!str) { - return; - } - this->WriteHeader(str); - - std::cout << "Writing " << fileName << "..." << std::endl; - - std::set<std::string> insertedConnections; - std::set<std::string> insertedNodes; - - for (auto const& ptr : this->TargetPtrs) { - if (ptr.second == nullptr) { - continue; - } - - if (!this->GenerateForTargetType(ptr.second->GetType())) { - continue; - } - - this->WriteConnections(ptr.first, insertedNodes, insertedConnections, str); - } - this->WriteFooter(str); + auto const escapedGraphName = EscapeForDotFile(name); + fs << "digraph \"" << escapedGraphName << "\" {" << std::endl; + fs << this->GraphHeader << std::endl; } -void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& str) const +void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& fs) { - str << this->GraphType << " \"" << this->GraphName << "\" {" << std::endl; - str << this->GraphHeader << std::endl; + fs << "}" << std::endl; } -void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& str) const +void cmGraphVizWriter::WriteLegend(cmGeneratedFileStream& fs) { - str << "}" << std::endl; + // Note that the subgraph name must start with "cluster", as done here, to + // make Graphviz layout engines do the right thing and keep the nodes + // together. + fs << "subgraph clusterLegend {" << std::endl; + fs << " label = \"Legend\";" << std::endl; + // Set the color of the box surrounding the legend. + fs << " color = black;" << std::endl; + // We use invisible edges just to enforce the layout. + fs << " edge [ style = invis ];" << std::endl; + + // Nodes. + fs << " legendNode0 [ label = \"Executable\", shape = " + << GRAPHVIZ_NODE_SHAPE_EXECUTABLE << " ];" << std::endl; + + fs << " legendNode1 [ label = \"Static Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC << " ];" << std::endl; + fs << " legendNode2 [ label = \"Shared Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED << " ];" << std::endl; + fs << " legendNode3 [ label = \"Module Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE << " ];" << std::endl; + + fs << " legendNode4 [ label = \"Interface Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE << " ];" << std::endl; + fs << " legendNode5 [ label = \"Object Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT << " ];" << std::endl; + fs << " legendNode6 [ label = \"Unknown Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN << " ];" << std::endl; + + fs << " legendNode7 [ label = \"Custom Target\", shape = " + << GRAPHVIZ_NODE_SHAPE_UTILITY << " ];" << std::endl; + + // Edges. + // Some of those are dummy (invisible) edges to enforce a layout. + fs << " legendNode0 -> legendNode1 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC + << " ];" << std::endl; + fs << " legendNode0 -> legendNode2 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC + << " ];" << std::endl; + fs << " legendNode0 -> legendNode3;" << std::endl; + + fs << " legendNode1 -> legendNode4 [ label = \"Interface\", style = " + << GRAPHVIZ_EDGE_STYLE_INTERFACE << " ];" << std::endl; + fs << " legendNode2 -> legendNode5 [ label = \"Private\", style = " + << GRAPHVIZ_EDGE_STYLE_PRIVATE << " ];" << std::endl; + fs << " legendNode3 -> legendNode6 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC + << " ];" << std::endl; + + fs << " legendNode0 -> legendNode7;" << std::endl; + + fs << "}" << std::endl; } -void cmGraphVizWriter::WriteConnections( - const std::string& targetName, std::set<std::string>& insertedNodes, - std::set<std::string>& insertedConnections, cmGeneratedFileStream& str) const +void cmGraphVizWriter::WriteNode(cmGeneratedFileStream& fs, + cmLinkItem const& item) { - auto targetPtrIt = this->TargetPtrs.find(targetName); + auto const& itemName = item.AsStr(); + auto const& nodeName = this->NodeNames[itemName]; - if (targetPtrIt == this->TargetPtrs.end()) // not found at all - { - return; - } - - this->WriteNode(targetName, targetPtrIt->second, insertedNodes, str); - - if (targetPtrIt->second == nullptr) // it's an external library - { - return; - } + auto const itemNameWithAliases = ItemNameWithAliases(itemName); + auto const escapedLabel = EscapeForDotFile(itemNameWithAliases); - std::string myNodeName = this->TargetNamesNodes.find(targetName)->second; - std::map<std::string, LinkLibraryScopeType> ll = - getScopedLinkLibrariesFromTarget(targetPtrIt->second->Target, - GlobalGenerator); - - for (auto const& llit : ll) { - const std::string& libName = llit.first; - auto libNameIt = this->TargetNamesNodes.find(libName); - - // can happen e.g. if GRAPHVIZ_TARGET_IGNORE_REGEX is used - if (libNameIt == this->TargetNamesNodes.end()) { - continue; - } + fs << " \"" << nodeName << "\" [ label = \"" << escapedLabel + << "\", shape = " << getShapeForTarget(item) << " ];" << std::endl; +} - std::string connectionName = cmStrCat(myNodeName, '-', libNameIt->second); - if (insertedConnections.find(connectionName) == - insertedConnections.end()) { - insertedConnections.insert(connectionName); - this->WriteNode(libName, this->TargetPtrs.find(libName)->second, - insertedNodes, str); +void cmGraphVizWriter::WriteConnection(cmGeneratedFileStream& fs, + cmLinkItem const& depender, + cmLinkItem const& dependee, + std::string const& edgeStyle) +{ + auto const& dependerName = depender.AsStr(); + auto const& dependeeName = dependee.AsStr(); - str << " \"" << myNodeName << "\" -> \"" << libNameIt->second << "\""; + fs << " \"" << this->NodeNames[dependerName] << "\" -> \"" + << this->NodeNames[dependeeName] << "\" "; - str << getLinkLibraryStyle(llit.second); + fs << edgeStyle; - str << " // " << targetName << " -> " << libName << std::endl; - this->WriteConnections(libName, insertedNodes, insertedConnections, str); - } - } + fs << " // " << dependerName << " -> " << dependeeName << std::endl; } -void cmGraphVizWriter::WriteDependerConnections( - const std::string& targetName, std::set<std::string>& insertedNodes, - std::set<std::string>& insertedConnections, cmGeneratedFileStream& str) const +bool cmGraphVizWriter::ItemExcluded(cmLinkItem const& item) { - auto targetPtrIt = this->TargetPtrs.find(targetName); + auto const itemName = item.AsStr(); - if (targetPtrIt == this->TargetPtrs.end()) // not found at all - { - return; + if (this->ItemNameFilteredOut(itemName)) { + return true; } - this->WriteNode(targetName, targetPtrIt->second, insertedNodes, str); - - if (targetPtrIt->second == nullptr) // it's an external library - { - return; + if (item.Target == nullptr) { + return !this->GenerateForExternals; } - std::string myNodeName = this->TargetNamesNodes.find(targetName)->second; - - // now search who links against me - for (auto const& tptr : this->TargetPtrs) { - if (tptr.second == nullptr) { - continue; - } - - if (!this->GenerateForTargetType(tptr.second->GetType())) { - continue; - } - - // Now we have a target, check whether it links against targetName. - // If so, draw a connection, and then continue with dependers on that one. - std::map<std::string, LinkLibraryScopeType> ll = - getScopedLinkLibrariesFromTarget(tptr.second->Target, GlobalGenerator); - - for (auto const& llit : ll) { - if (llit.first == targetName) { - // So this target links against targetName. - auto dependerNodeNameIt = this->TargetNamesNodes.find(tptr.first); - - if (dependerNodeNameIt != this->TargetNamesNodes.end()) { - std::string connectionName = - cmStrCat(dependerNodeNameIt->second, '-', myNodeName); - - if (insertedConnections.find(connectionName) == - insertedConnections.end()) { - insertedConnections.insert(connectionName); - this->WriteNode(tptr.first, tptr.second, insertedNodes, str); - - str << " \"" << dependerNodeNameIt->second << "\" -> \"" - << myNodeName << "\""; - str << " // " << targetName << " -> " << tptr.first << std::endl; - str << getLinkLibraryStyle(llit.second); - this->WriteDependerConnections(tptr.first, insertedNodes, - insertedConnections, str); - } - } - break; - } + if (item.Target->GetType() == cmStateEnums::UTILITY) { + if ((itemName.find("Nightly") == 0) || + (itemName.find("Continuous") == 0) || + (itemName.find("Experimental") == 0)) { + return true; } } -} -void cmGraphVizWriter::WriteNode(const std::string& targetName, - const cmGeneratorTarget* target, - std::set<std::string>& insertedNodes, - cmGeneratedFileStream& str) const -{ - if (insertedNodes.find(targetName) == insertedNodes.end()) { - insertedNodes.insert(targetName); - auto nameIt = this->TargetNamesNodes.find(targetName); - - str << " \"" << nameIt->second << "\" [ label=\"" << targetName - << "\" shape=\"" << getShapeForTarget(target) << "\"];" << std::endl; + if (item.Target->IsImported() && !this->GenerateForExternals) { + return true; } -} -void cmGraphVizWriter::CollectTargetsAndLibs() -{ - if (!this->HaveTargetsAndLibs) { - this->HaveTargetsAndLibs = true; - int cnt = this->CollectAllTargets(); - if (this->GenerateForExternals) { - this->CollectAllExternalLibs(cnt); - } - } + return !this->TargetTypeEnabled(item.Target->GetType()); } -int cmGraphVizWriter::CollectAllTargets() +bool cmGraphVizWriter::ItemNameFilteredOut(std::string const& itemName) { - int cnt = 0; - // First pass get the list of all cmake targets - for (cmLocalGenerator* lg : this->LocalGenerators) { - const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { - const std::string& realTargetName = target->GetName(); - if (this->IgnoreThisTarget(realTargetName)) { - // Skip ignored targets - continue; - } - // std::cout << "Found target: " << tit->first << std::endl; - std::ostringstream ostr; - ostr << this->GraphNodePrefix << cnt++; - this->TargetNamesNodes[realTargetName] = ostr.str(); - this->TargetPtrs[realTargetName] = target; - } + if (itemName == ">") { + // FIXME: why do we even receive such a target here? + return true; } - return cnt; -} - -int cmGraphVizWriter::CollectAllExternalLibs(int cnt) -{ - // Ok, now find all the stuff we link to that is not in cmake - for (cmLocalGenerator* lg : this->LocalGenerators) { - const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { - const std::string& realTargetName = target->GetName(); - if (this->IgnoreThisTarget(realTargetName)) { - // Skip ignored targets - continue; - } - const cmTarget::LinkLibraryVectorType* ll = - &(target->Target->GetOriginalLinkLibraries()); - for (auto const& llit : *ll) { - std::string libName = llit.first; - if (this->IgnoreThisTarget(libName)) { - // Skip ignored targets - continue; - } - - if (GlobalGenerator->IsAlias(libName)) { - const auto tgt = GlobalGenerator->FindTarget(libName); - if (tgt) { - libName = tgt->GetName(); - } - } - - auto tarIt = this->TargetPtrs.find(libName); - if (tarIt == this->TargetPtrs.end()) { - std::ostringstream ostr; - ostr << this->GraphNodePrefix << cnt++; - this->TargetNamesNodes[libName] = ostr.str(); - this->TargetPtrs[libName] = nullptr; - // str << " \"" << ostr << "\" [ label=\"" << libName - // << "\" shape=\"ellipse\"];" << std::endl; - } - } - } + if (cmGlobalGenerator::IsReservedTarget(itemName)) { + return true; } - return cnt; -} -bool cmGraphVizWriter::IgnoreThisTarget(const std::string& name) -{ for (cmsys::RegularExpression& regEx : this->TargetsToIgnoreRegex) { if (regEx.is_valid()) { - if (regEx.find(name)) { + if (regEx.find(itemName)) { return true; } } @@ -579,7 +438,7 @@ bool cmGraphVizWriter::IgnoreThisTarget(const std::string& name) return false; } -bool cmGraphVizWriter::GenerateForTargetType( +bool cmGraphVizWriter::TargetTypeEnabled( cmStateEnums::TargetType targetType) const { switch (targetType) { @@ -592,9 +451,73 @@ bool cmGraphVizWriter::GenerateForTargetType( case cmStateEnums::MODULE_LIBRARY: return this->GenerateForModuleLibs; case cmStateEnums::INTERFACE_LIBRARY: - return this->GenerateForInterface; + return this->GenerateForInterfaceLibs; + case cmStateEnums::OBJECT_LIBRARY: + return this->GenerateForObjectLibs; + case cmStateEnums::UNKNOWN_LIBRARY: + return this->GenerateForUnknownLibs; + case cmStateEnums::UTILITY: + return this->GenerateForCustomTargets; + case cmStateEnums::GLOBAL_TARGET: + // Built-in targets like edit_cache, etc. + // We don't need/want those in the dot file. + return false; default: break; } return false; } + +std::string cmGraphVizWriter::ItemNameWithAliases( + std::string const& itemName) const +{ + auto nameWithAliases = itemName; + + for (auto const& lg : this->GlobalGenerator->GetLocalGenerators()) { + for (auto const& aliasTargets : lg->GetMakefile()->GetAliasTargets()) { + if (aliasTargets.second == itemName) { + nameWithAliases += "\\n(" + aliasTargets.first + ")"; + } + } + } + + return nameWithAliases; +} + +std::string cmGraphVizWriter::GetEdgeStyle(DependencyType dt) +{ + std::string style; + switch (dt) { + case DependencyType::LinkPrivate: + style = "[ style = " + std::string(GRAPHVIZ_EDGE_STYLE_PRIVATE) + " ]"; + break; + case DependencyType::LinkInterface: + style = "[ style = " + std::string(GRAPHVIZ_EDGE_STYLE_INTERFACE) + " ]"; + break; + default: + break; + } + return style; +} + +std::string cmGraphVizWriter::EscapeForDotFile(std::string const& str) +{ + return cmSystemTools::EscapeChars(str.data(), "\""); +} + +std::string cmGraphVizWriter::PathSafeString(std::string const& str) +{ + std::string pathSafeStr; + + // We'll only keep alphanumerical characters, plus the following ones that + // are common, and safe on all platforms: + auto const extra_chars = std::set<char>{ '.', '-', '_' }; + + for (char c : str) { + if (std::isalnum(c) || extra_chars.find(c) != extra_chars.cend()) { + pathSafeStr += c; + } + } + + return pathSafeStr; +} diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h index 9c3051f..578660d 100644 --- a/Source/cmGraphVizWriter.h +++ b/Source/cmGraphVizWriter.h @@ -6,87 +6,106 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <map> -#include <set> +#include <memory> #include <string> #include <vector> #include "cmsys/RegularExpression.hxx" +#include "cmGeneratedFileStream.h" +#include "cmLinkItemGraphVisitor.h" #include "cmStateTypes.h" -class cmGeneratedFileStream; -class cmGeneratorTarget; -class cmLocalGenerator; +class cmLinkItem; class cmGlobalGenerator; /** This class implements writing files for graphviz (dot) for graphs * representing the dependencies between the targets in the project. */ -class cmGraphVizWriter +class cmGraphVizWriter : public cmLinkItemGraphVisitor { public: - cmGraphVizWriter(const cmGlobalGenerator* globalGenerator); + cmGraphVizWriter(std::string const& fileName, + const cmGlobalGenerator* globalGenerator); + ~cmGraphVizWriter() override; + + void VisitGraph(std::string const& name) override; + + void OnItem(cmLinkItem const& item) override; + + void OnDirectLink(cmLinkItem const& depender, cmLinkItem const& dependee, + DependencyType dt) override; + + void OnIndirectLink(cmLinkItem const& depender, + cmLinkItem const& dependee) override; void ReadSettings(const std::string& settingsFileName, const std::string& fallbackSettingsFileName); - void WritePerTargetFiles(const std::string& fileName); - void WriteTargetDependersFiles(const std::string& fileName); + void Write(); + +private: + using FileStreamMap = + std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>; + + void VisitLink(cmLinkItem const& depender, cmLinkItem const& dependee, + bool isDirectLink, std::string const& scopeType = ""); + + void WriteHeader(cmGeneratedFileStream& fs, std::string const& name); - void WriteGlobalFile(const std::string& fileName); + void WriteFooter(cmGeneratedFileStream& fs); -protected: - void CollectTargetsAndLibs(); + void WriteLegend(cmGeneratedFileStream& fs); - int CollectAllTargets(); + void WriteNode(cmGeneratedFileStream& fs, cmLinkItem const& item); - int CollectAllExternalLibs(int cnt); + void CreateTargetFile(FileStreamMap& fileStreamMap, cmLinkItem const& target, + std::string const& fileNameSuffix = ""); - void WriteHeader(cmGeneratedFileStream& str) const; + void WriteConnection(cmGeneratedFileStream& fs, + cmLinkItem const& dependerTargetName, + cmLinkItem const& dependeeTargetName, + std::string const& edgeStyle); - void WriteConnections(const std::string& targetName, - std::set<std::string>& insertedNodes, - std::set<std::string>& insertedConnections, - cmGeneratedFileStream& str) const; + bool ItemExcluded(cmLinkItem const& item); + bool ItemNameFilteredOut(std::string const& itemName); + bool TargetTypeEnabled(cmStateEnums::TargetType targetType) const; - void WriteDependerConnections(const std::string& targetName, - std::set<std::string>& insertedNodes, - std::set<std::string>& insertedConnections, - cmGeneratedFileStream& str) const; + std::string ItemNameWithAliases(std::string const& itemName) const; - void WriteNode(const std::string& targetName, - const cmGeneratorTarget* target, - std::set<std::string>& insertedNodes, - cmGeneratedFileStream& str) const; + static std::string GetEdgeStyle(DependencyType dt); - void WriteFooter(cmGeneratedFileStream& str) const; + static std::string EscapeForDotFile(std::string const& str); - bool IgnoreThisTarget(const std::string& name); + static std::string PathSafeString(std::string const& str); - bool GenerateForTargetType(cmStateEnums::TargetType targetType) const; + std::string FileName; + cmGeneratedFileStream GlobalFileStream; + FileStreamMap PerTargetFileStreams; + FileStreamMap TargetDependersFileStreams; - std::string GraphType; std::string GraphName; std::string GraphHeader; std::string GraphNodePrefix; std::vector<cmsys::RegularExpression> TargetsToIgnoreRegex; - const cmGlobalGenerator* GlobalGenerator; - const std::vector<cmLocalGenerator*>& LocalGenerators; + cmGlobalGenerator const* GlobalGenerator; - std::map<std::string, const cmGeneratorTarget*> TargetPtrs; - // maps from the actual target names to node names in dot: - std::map<std::string, std::string> TargetNamesNodes; + int NextNodeId; + // maps from the actual item names to node names in dot: + std::map<std::string, std::string> NodeNames; bool GenerateForExecutables; bool GenerateForStaticLibs; bool GenerateForSharedLibs; bool GenerateForModuleLibs; - bool GenerateForInterface; + bool GenerateForInterfaceLibs; + bool GenerateForObjectLibs; + bool GenerateForUnknownLibs; + bool GenerateForCustomTargets; bool GenerateForExternals; bool GeneratePerTarget; bool GenerateDependers; - bool HaveTargetsAndLibs; }; #endif diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx index 71326d2..b53319f 100644 --- a/Source/cmIDEOptions.cxx +++ b/Source/cmIDEOptions.cxx @@ -4,6 +4,8 @@ #include <iterator> +#include <cmext/algorithm> + #include <string.h> #include "cmsys/String.h" @@ -173,7 +175,7 @@ void cmIDEOptions::AddDefines(std::string const& defines) } void cmIDEOptions::AddDefines(const std::vector<std::string>& defines) { - cmAppend(this->Defines, defines); + cm::append(this->Defines, defines); } std::vector<std::string> const& cmIDEOptions::GetDefines() const @@ -195,7 +197,7 @@ void cmIDEOptions::AddIncludes(std::string const& includes) } void cmIDEOptions::AddIncludes(const std::vector<std::string>& includes) { - cmAppend(this->Includes, includes); + cm::append(this->Includes, includes); } std::vector<std::string> const& cmIDEOptions::GetIncludes() const diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx index 170aea1..b408f72 100644 --- a/Source/cmIncludeDirectoryCommand.cxx +++ b/Source/cmIncludeDirectoryCommand.cxx @@ -6,7 +6,8 @@ #include <set> #include <utility> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" #include "cmMakefile.h" @@ -58,9 +59,9 @@ bool cmIncludeDirectoryCommand(std::vector<std::string> const& args, GetIncludes(mf, *i, includes); if (before) { - cmAppend(beforeIncludes, includes); + cm::append(beforeIncludes, includes); } else { - cmAppend(afterIncludes, includes); + cm::append(afterIncludes, includes); } if (system) { systemIncludes.insert(includes.begin(), includes.end()); diff --git a/Source/cmIncludeExternalMSProjectCommand.cxx b/Source/cmIncludeExternalMSProjectCommand.cxx index fa1e8bc..5b532ce 100644 --- a/Source/cmIncludeExternalMSProjectCommand.cxx +++ b/Source/cmIncludeExternalMSProjectCommand.cxx @@ -77,28 +77,27 @@ bool cmIncludeExternalMSProjectCommand(std::vector<std::string> const& args, if (!customGuid.empty()) { std::string guidVariable = utility_name + "_GUID_CMAKE"; - mf.GetCMakeInstance()->AddCacheEntry(guidVariable.c_str(), - customGuid.c_str(), "Stored GUID", + mf.GetCMakeInstance()->AddCacheEntry(guidVariable, customGuid.c_str(), + "Stored GUID", cmStateEnums::INTERNAL); } // Create a target instance for this utility. - cmTarget* target = - mf.AddNewTarget(cmStateEnums::UTILITY, utility_name.c_str()); + cmTarget* target = mf.AddNewTarget(cmStateEnums::UTILITY, utility_name); if (mf.GetPropertyAsBool("EXCLUDE_FROM_ALL")) { target->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); } - target->SetProperty("GENERATOR_FILE_NAME", utility_name.c_str()); - target->SetProperty("EXTERNAL_MSPROJECT", path.c_str()); + target->SetProperty("GENERATOR_FILE_NAME", utility_name); + target->SetProperty("EXTERNAL_MSPROJECT", path); if (!customType.empty()) - target->SetProperty("VS_PROJECT_TYPE", customType.c_str()); + target->SetProperty("VS_PROJECT_TYPE", customType); if (!platformMapping.empty()) - target->SetProperty("VS_PLATFORM_MAPPING", platformMapping.c_str()); + target->SetProperty("VS_PLATFORM_MAPPING", platformMapping); for (std::string const& d : depends) { - target->AddUtility(d.c_str()); + target->AddUtility(d, false); } } #endif diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index e511196..d669ed7 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -85,7 +85,7 @@ public: std::string DefaultComponentName; }; -cmInstallTargetGenerator* CreateInstallTargetGenerator( +std::unique_ptr<cmInstallTargetGenerator> CreateInstallTargetGenerator( cmTarget& target, const cmInstallCommandArguments& args, bool impLib, cmListFileBacktrace const& backtrace, const std::string& destination, bool forceOpt = false, bool namelink = false) @@ -93,18 +93,17 @@ cmInstallTargetGenerator* CreateInstallTargetGenerator( cmInstallGenerator::MessageLevel message = cmInstallGenerator::SelectMessageLevel(target.GetMakefile()); target.SetHaveInstallRule(true); - const char* component = namelink ? args.GetNamelinkComponent().c_str() - : args.GetComponent().c_str(); - auto g = new cmInstallTargetGenerator( - target.GetName(), destination.c_str(), impLib, - args.GetPermissions().c_str(), args.GetConfigurations(), component, - message, args.GetExcludeFromAll(), args.GetOptional() || forceOpt, - backtrace); - target.AddInstallGenerator(g); + const std::string& component = + namelink ? args.GetNamelinkComponent() : args.GetComponent(); + auto g = cm::make_unique<cmInstallTargetGenerator>( + target.GetName(), destination, impLib, args.GetPermissions(), + args.GetConfigurations(), component, message, args.GetExcludeFromAll(), + args.GetOptional() || forceOpt, backtrace); + target.AddInstallGenerator(g.get()); return g; } -cmInstallTargetGenerator* CreateInstallTargetGenerator( +std::unique_ptr<cmInstallTargetGenerator> CreateInstallTargetGenerator( cmTarget& target, const cmInstallCommandArguments& args, bool impLib, cmListFileBacktrace const& backtrace, bool forceOpt = false, bool namelink = false) @@ -114,20 +113,20 @@ cmInstallTargetGenerator* CreateInstallTargetGenerator( namelink); } -cmInstallFilesGenerator* CreateInstallFilesGenerator( +std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator( cmMakefile* mf, const std::vector<std::string>& absFiles, const cmInstallCommandArguments& args, bool programs, const std::string& destination) { cmInstallGenerator::MessageLevel message = cmInstallGenerator::SelectMessageLevel(mf); - return new cmInstallFilesGenerator( - absFiles, destination.c_str(), programs, args.GetPermissions().c_str(), - args.GetConfigurations(), args.GetComponent().c_str(), message, - args.GetExcludeFromAll(), args.GetRename().c_str(), args.GetOptional()); + return cm::make_unique<cmInstallFilesGenerator>( + absFiles, destination, programs, args.GetPermissions(), + args.GetConfigurations(), args.GetComponent(), message, + args.GetExcludeFromAll(), args.GetRename(), args.GetOptional()); } -cmInstallFilesGenerator* CreateInstallFilesGenerator( +std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator( cmMakefile* mf, const std::vector<std::string>& absFiles, const cmInstallCommandArguments& args, bool programs) { @@ -196,13 +195,15 @@ bool HandleScriptMode(std::vector<std::string> const& args, status.SetError("given a directory as value of SCRIPT argument."); return false; } - helper.Makefile->AddInstallGenerator(new cmInstallScriptGenerator( - script.c_str(), false, component.c_str(), exclude_from_all)); + helper.Makefile->AddInstallGenerator( + cm::make_unique<cmInstallScriptGenerator>(script, false, component, + exclude_from_all)); } else if (doing_code) { doing_code = false; std::string const& code = arg; - helper.Makefile->AddInstallGenerator(new cmInstallScriptGenerator( - code.c_str(), true, component.c_str(), exclude_from_all)); + helper.Makefile->AddInstallGenerator( + cm::make_unique<cmInstallScriptGenerator>(code, true, component, + exclude_from_all)); } } @@ -449,16 +450,16 @@ bool HandleTargetsMode(std::vector<std::string> const& args, for (cmTarget* ti : targets) { // Handle each target type. cmTarget& target = *ti; - cmInstallTargetGenerator* archiveGenerator = nullptr; - cmInstallTargetGenerator* libraryGenerator = nullptr; - cmInstallTargetGenerator* namelinkGenerator = nullptr; - cmInstallTargetGenerator* runtimeGenerator = nullptr; - cmInstallTargetGenerator* objectGenerator = nullptr; - cmInstallTargetGenerator* frameworkGenerator = nullptr; - cmInstallTargetGenerator* bundleGenerator = nullptr; - cmInstallFilesGenerator* privateHeaderGenerator = nullptr; - cmInstallFilesGenerator* publicHeaderGenerator = nullptr; - cmInstallFilesGenerator* resourceGenerator = nullptr; + std::unique_ptr<cmInstallTargetGenerator> archiveGenerator; + std::unique_ptr<cmInstallTargetGenerator> libraryGenerator; + std::unique_ptr<cmInstallTargetGenerator> namelinkGenerator; + std::unique_ptr<cmInstallTargetGenerator> runtimeGenerator; + std::unique_ptr<cmInstallTargetGenerator> objectGenerator; + std::unique_ptr<cmInstallTargetGenerator> frameworkGenerator; + std::unique_ptr<cmInstallTargetGenerator> bundleGenerator; + std::unique_ptr<cmInstallFilesGenerator> privateHeaderGenerator; + std::unique_ptr<cmInstallFilesGenerator> publicHeaderGenerator; + std::unique_ptr<cmInstallFilesGenerator> resourceGenerator; // Avoid selecting default destinations for PUBLIC_HEADER and // PRIVATE_HEADER if any artifacts are specified. @@ -491,7 +492,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, target, runtimeArgs, false, helper.Makefile->GetBacktrace()); artifactsSpecified = true; } - if ((archiveGenerator == nullptr) && (runtimeGenerator == nullptr)) { + if (!archiveGenerator && !runtimeGenerator) { archiveGenerator = CreateInstallTargetGenerator( target, archiveArgs, true, helper.Makefile->GetBacktrace(), helper.GetArchiveDestination(nullptr)); @@ -744,43 +745,18 @@ bool HandleTargetsMode(std::vector<std::string> const& args, } } - // Keep track of whether we're installing anything in each category - installsArchive = installsArchive || archiveGenerator != nullptr; - installsLibrary = installsLibrary || libraryGenerator != nullptr; - installsNamelink = installsNamelink || namelinkGenerator != nullptr; - installsRuntime = installsRuntime || runtimeGenerator != nullptr; - installsObject = installsObject || objectGenerator != nullptr; - installsFramework = installsFramework || frameworkGenerator != nullptr; - installsBundle = installsBundle || bundleGenerator != nullptr; - installsPrivateHeader = - installsPrivateHeader || privateHeaderGenerator != nullptr; - installsPublicHeader = - installsPublicHeader || publicHeaderGenerator != nullptr; - installsResource = installsResource || resourceGenerator; - - helper.Makefile->AddInstallGenerator(archiveGenerator); - helper.Makefile->AddInstallGenerator(libraryGenerator); - helper.Makefile->AddInstallGenerator(namelinkGenerator); - helper.Makefile->AddInstallGenerator(runtimeGenerator); - helper.Makefile->AddInstallGenerator(objectGenerator); - helper.Makefile->AddInstallGenerator(frameworkGenerator); - helper.Makefile->AddInstallGenerator(bundleGenerator); - helper.Makefile->AddInstallGenerator(privateHeaderGenerator); - helper.Makefile->AddInstallGenerator(publicHeaderGenerator); - helper.Makefile->AddInstallGenerator(resourceGenerator); - // Add this install rule to an export if one was specified and // this is not a namelink-only rule. if (!exports.empty() && !namelinkOnly) { auto te = cm::make_unique<cmTargetExport>(); te->TargetName = target.GetName(); - te->ArchiveGenerator = archiveGenerator; - te->BundleGenerator = bundleGenerator; - te->FrameworkGenerator = frameworkGenerator; - te->HeaderGenerator = publicHeaderGenerator; - te->LibraryGenerator = libraryGenerator; - te->RuntimeGenerator = runtimeGenerator; - te->ObjectsGenerator = objectGenerator; + te->ArchiveGenerator = archiveGenerator.get(); + te->BundleGenerator = bundleGenerator.get(); + te->FrameworkGenerator = frameworkGenerator.get(); + te->HeaderGenerator = publicHeaderGenerator.get(); + te->LibraryGenerator = libraryGenerator.get(); + te->RuntimeGenerator = runtimeGenerator.get(); + te->ObjectsGenerator = objectGenerator.get(); te->InterfaceIncludeDirectories = cmJoin(includesArgs.GetIncludeDirs(), ";"); @@ -788,6 +764,29 @@ bool HandleTargetsMode(std::vector<std::string> const& args, ->GetExportSets()[exports] .AddTargetExport(std::move(te)); } + + // Keep track of whether we're installing anything in each category + installsArchive = installsArchive || archiveGenerator; + installsLibrary = installsLibrary || libraryGenerator; + installsNamelink = installsNamelink || namelinkGenerator; + installsRuntime = installsRuntime || runtimeGenerator; + installsObject = installsObject || objectGenerator; + installsFramework = installsFramework || frameworkGenerator; + installsBundle = installsBundle || bundleGenerator; + installsPrivateHeader = installsPrivateHeader || privateHeaderGenerator; + installsPublicHeader = installsPublicHeader || publicHeaderGenerator; + installsResource = installsResource || resourceGenerator; + + helper.Makefile->AddInstallGenerator(std::move(archiveGenerator)); + helper.Makefile->AddInstallGenerator(std::move(libraryGenerator)); + helper.Makefile->AddInstallGenerator(std::move(namelinkGenerator)); + helper.Makefile->AddInstallGenerator(std::move(runtimeGenerator)); + helper.Makefile->AddInstallGenerator(std::move(objectGenerator)); + helper.Makefile->AddInstallGenerator(std::move(frameworkGenerator)); + helper.Makefile->AddInstallGenerator(std::move(bundleGenerator)); + helper.Makefile->AddInstallGenerator(std::move(privateHeaderGenerator)); + helper.Makefile->AddInstallGenerator(std::move(publicHeaderGenerator)); + helper.Makefile->AddInstallGenerator(std::move(resourceGenerator)); } // Tell the global generator about any installation component names @@ -975,7 +974,7 @@ bool HandleDirectoryMode(std::vector<std::string> const& args, bool exclude_from_all = false; bool message_never = false; std::vector<std::string> dirs; - const char* destination = nullptr; + const std::string* destination = nullptr; std::string permissions_file; std::string permissions_dir; std::vector<std::string> configurations; @@ -1134,7 +1133,7 @@ bool HandleDirectoryMode(std::vector<std::string> const& args, } else if (doing == DoingConfigurations) { configurations.push_back(args[i]); } else if (doing == DoingDestination) { - destination = args[i].c_str(); + destination = &args[i]; doing = DoingNone; } else if (doing == DoingType) { if (allowedTypes.count(args[i]) == 0) { @@ -1220,7 +1219,7 @@ bool HandleDirectoryMode(std::vector<std::string> const& args, return false; } destinationStr = helper.GetDestinationForType(nullptr, type); - destination = destinationStr.c_str(); + destination = &destinationStr; } else if (!type.empty()) { status.SetError(cmStrCat(args[0], " given both TYPE and DESTINATION " @@ -1232,10 +1231,10 @@ bool HandleDirectoryMode(std::vector<std::string> const& args, cmInstallGenerator::SelectMessageLevel(helper.Makefile, message_never); // Create the directory install generator. - helper.Makefile->AddInstallGenerator(new cmInstallDirectoryGenerator( - dirs, destination, permissions_file.c_str(), permissions_dir.c_str(), - configurations, component.c_str(), message, exclude_from_all, - literal_args.c_str(), optional)); + helper.Makefile->AddInstallGenerator( + cm::make_unique<cmInstallDirectoryGenerator>( + dirs, *destination, permissions_file, permissions_dir, configurations, + component, message, exclude_from_all, literal_args, optional)); // Tell the global generator about any installation component names // specified. @@ -1323,12 +1322,11 @@ bool HandleExportAndroidMKMode(std::vector<std::string> const& args, cmInstallGenerator::SelectMessageLevel(helper.Makefile); // Create the export install generator. - cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator( - &exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(), - ica.GetConfigurations(), ica.GetComponent().c_str(), message, - ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld, - true); - helper.Makefile->AddInstallGenerator(exportGenerator); + helper.Makefile->AddInstallGenerator( + cm::make_unique<cmInstallExportGenerator>( + &exportSet, ica.GetDestination(), ica.GetPermissions(), + ica.GetConfigurations(), ica.GetComponent(), message, + ica.GetExcludeFromAll(), fname, name_space, exportOld, true)); return true; #else @@ -1437,12 +1435,11 @@ bool HandleExportMode(std::vector<std::string> const& args, cmInstallGenerator::SelectMessageLevel(helper.Makefile); // Create the export install generator. - cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator( - &exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(), - ica.GetConfigurations(), ica.GetComponent().c_str(), message, - ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld, - false); - helper.Makefile->AddInstallGenerator(exportGenerator); + helper.Makefile->AddInstallGenerator( + cm::make_unique<cmInstallExportGenerator>( + &exportSet, ica.GetDestination(), ica.GetPermissions(), + ica.GetConfigurations(), ica.GetComponent(), message, + ica.GetExcludeFromAll(), fname, name_space, exportOld, false)); return true; } diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx index 259c7f7..175e7cf 100644 --- a/Source/cmInstallDirectoryGenerator.cxx +++ b/Source/cmInstallDirectoryGenerator.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmInstallDirectoryGenerator.h" +#include <utility> + #include "cmGeneratorExpression.h" #include "cmInstallType.h" #include "cmLocalGenerator.h" @@ -10,18 +12,18 @@ #include "cmSystemTools.h" cmInstallDirectoryGenerator::cmInstallDirectoryGenerator( - std::vector<std::string> const& dirs, const char* dest, - const char* file_permissions, const char* dir_permissions, - std::vector<std::string> const& configurations, const char* component, - MessageLevel message, bool exclude_from_all, const char* literal_args, + std::vector<std::string> const& dirs, std::string const& dest, + std::string file_permissions, std::string dir_permissions, + std::vector<std::string> const& configurations, std::string const& component, + MessageLevel message, bool exclude_from_all, std::string literal_args, bool optional) : cmInstallGenerator(dest, configurations, component, message, exclude_from_all) , LocalGenerator(nullptr) , Directories(dirs) - , FilePermissions(file_permissions) - , DirPermissions(dir_permissions) - , LiteralArguments(literal_args) + , FilePermissions(std::move(file_permissions)) + , DirPermissions(std::move(dir_permissions)) + , LiteralArguments(std::move(literal_args)) , Optional(optional) { // We need per-config actions if destination have generator expressions. diff --git a/Source/cmInstallDirectoryGenerator.h b/Source/cmInstallDirectoryGenerator.h index 84c0694..bec89df 100644 --- a/Source/cmInstallDirectoryGenerator.h +++ b/Source/cmInstallDirectoryGenerator.h @@ -21,12 +21,13 @@ class cmInstallDirectoryGenerator : public cmInstallGenerator { public: cmInstallDirectoryGenerator(std::vector<std::string> const& dirs, - const char* dest, const char* file_permissions, - const char* dir_permissions, + std::string const& dest, + std::string file_permissions, + std::string dir_permissions, std::vector<std::string> const& configurations, - const char* component, MessageLevel message, - bool exclude_from_all, const char* literal_args, - bool optional = false); + std::string const& component, + MessageLevel message, bool exclude_from_all, + std::string literal_args, bool optional = false); ~cmInstallDirectoryGenerator() override; bool Compute(cmLocalGenerator* lg) override; @@ -41,11 +42,11 @@ protected: Indent indent, std::vector<std::string> const& dirs); cmLocalGenerator* LocalGenerator; - std::vector<std::string> Directories; - std::string FilePermissions; - std::string DirPermissions; - std::string LiteralArguments; - bool Optional; + std::vector<std::string> const Directories; + std::string const FilePermissions; + std::string const DirPermissions; + std::string const LiteralArguments; + bool const Optional; }; #endif diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index cba68be..6e3508c 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -7,6 +7,8 @@ #include <sstream> #include <utility> +#include <cm/memory> + #ifndef CMAKE_BOOTSTRAP # include "cmExportInstallAndroidMKGenerator.h" #endif @@ -18,33 +20,30 @@ #include "cmSystemTools.h" cmInstallExportGenerator::cmInstallExportGenerator( - cmExportSet* exportSet, const char* destination, - const char* file_permissions, std::vector<std::string> const& configurations, - const char* component, MessageLevel message, bool exclude_from_all, - const char* filename, const char* name_space, bool exportOld, bool android) + cmExportSet* exportSet, std::string const& destination, + std::string file_permissions, std::vector<std::string> const& configurations, + std::string const& component, MessageLevel message, bool exclude_from_all, + std::string filename, std::string name_space, bool exportOld, bool android) : cmInstallGenerator(destination, configurations, component, message, exclude_from_all) , ExportSet(exportSet) - , FilePermissions(file_permissions) - , FileName(filename) - , Namespace(name_space) + , FilePermissions(std::move(file_permissions)) + , FileName(std::move(filename)) + , Namespace(std::move(name_space)) , ExportOld(exportOld) , LocalGenerator(nullptr) { if (android) { #ifndef CMAKE_BOOTSTRAP - this->EFGen = new cmExportInstallAndroidMKGenerator(this); + this->EFGen = cm::make_unique<cmExportInstallAndroidMKGenerator>(this); #endif } else { - this->EFGen = new cmExportInstallFileGenerator(this); + this->EFGen = cm::make_unique<cmExportInstallFileGenerator>(this); } exportSet->AddInstallation(this); } -cmInstallExportGenerator::~cmInstallExportGenerator() -{ - delete this->EFGen; -} +cmInstallExportGenerator::~cmInstallExportGenerator() = default; bool cmInstallExportGenerator::Compute(cmLocalGenerator* lg) { diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h index f44127e..43dd00d 100644 --- a/Source/cmInstallExportGenerator.h +++ b/Source/cmInstallExportGenerator.h @@ -7,6 +7,7 @@ #include <cstddef> #include <iosfwd> +#include <memory> #include <string> #include <vector> @@ -23,15 +24,19 @@ class cmLocalGenerator; class cmInstallExportGenerator : public cmInstallGenerator { public: - cmInstallExportGenerator(cmExportSet* exportSet, const char* dest, - const char* file_permissions, + cmInstallExportGenerator(cmExportSet* exportSet, std::string const& dest, + std::string file_permissions, const std::vector<std::string>& configurations, - const char* component, MessageLevel message, - bool exclude_from_all, const char* filename, - const char* name_space, bool exportOld, + std::string const& component, MessageLevel message, + bool exclude_from_all, std::string filename, + std::string name_space, bool exportOld, bool android); + cmInstallExportGenerator(const cmInstallExportGenerator&) = delete; ~cmInstallExportGenerator() override; + cmInstallExportGenerator& operator=(const cmInstallExportGenerator&) = + delete; + cmExportSet* GetExportSet() { return this->ExportSet; } bool Compute(cmLocalGenerator* lg) override; @@ -52,16 +57,16 @@ protected: void ComputeTempDir(); size_t GetMaxConfigLength() const; - cmExportSet* ExportSet; - std::string FilePermissions; - std::string FileName; - std::string Namespace; - bool ExportOld; + cmExportSet* const ExportSet; + std::string const FilePermissions; + std::string const FileName; + std::string const Namespace; + bool const ExportOld; cmLocalGenerator* LocalGenerator; std::string TempDir; std::string MainImportFile; - cmExportInstallFileGenerator* EFGen; + std::unique_ptr<cmExportInstallFileGenerator> EFGen; }; #endif diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx index d623943..3c59f01 100644 --- a/Source/cmInstallFilesCommand.cxx +++ b/Source/cmInstallFilesCommand.cxx @@ -2,16 +2,21 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmInstallFilesCommand.h" +#include <cm/memory> + #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" #include "cmInstallFilesGenerator.h" #include "cmInstallGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmRange.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +class cmListFileBacktrace; + static std::string FindInstallSource(cmMakefile& makefile, const char* name); static void CreateInstallGenerator(cmMakefile& makefile, std::string const& dest, @@ -43,9 +48,10 @@ bool cmInstallFilesCommand(std::vector<std::string> const& args, CreateInstallGenerator(mf, dest, files); } else { std::vector<std::string> finalArgs(args.begin() + 1, args.end()); - mf.AddFinalAction([dest, finalArgs](cmMakefile& makefile) { - FinalAction(makefile, dest, finalArgs); - }); + mf.AddGeneratorAction( + [dest, finalArgs](cmLocalGenerator& lg, const cmListFileBacktrace&) { + FinalAction(*lg.GetMakefile(), dest, finalArgs); + }); } mf.GetGlobalGenerator()->AddInstallComponent( @@ -109,17 +115,17 @@ static void CreateInstallGenerator(cmMakefile& makefile, } // Use a file install generator. - const char* no_permissions = ""; - const char* no_rename = ""; + const std::string no_permissions; + const std::string no_rename; bool no_exclude_from_all = false; std::string no_component = makefile.GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"); std::vector<std::string> no_configurations; cmInstallGenerator::MessageLevel message = cmInstallGenerator::SelectMessageLevel(&makefile); - makefile.AddInstallGenerator(new cmInstallFilesGenerator( - files, destination.c_str(), false, no_permissions, no_configurations, - no_component.c_str(), message, no_exclude_from_all, no_rename)); + makefile.AddInstallGenerator(cm::make_unique<cmInstallFilesGenerator>( + files, destination, false, no_permissions, no_configurations, no_component, + message, no_exclude_from_all, no_rename)); } /** diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx index f5b69a5..ad2f84e 100644 --- a/Source/cmInstallFilesGenerator.cxx +++ b/Source/cmInstallFilesGenerator.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmInstallFilesGenerator.h" +#include <utility> + #include "cmGeneratorExpression.h" #include "cmInstallType.h" #include "cmStringAlgorithms.h" @@ -9,16 +11,17 @@ class cmLocalGenerator; cmInstallFilesGenerator::cmInstallFilesGenerator( - std::vector<std::string> const& files, const char* dest, bool programs, - const char* file_permissions, std::vector<std::string> const& configurations, - const char* component, MessageLevel message, bool exclude_from_all, - const char* rename, bool optional) + std::vector<std::string> const& files, std::string const& dest, + bool programs, std::string file_permissions, + std::vector<std::string> const& configurations, std::string const& component, + MessageLevel message, bool exclude_from_all, std::string rename, + bool optional) : cmInstallGenerator(dest, configurations, component, message, exclude_from_all) , LocalGenerator(nullptr) , Files(files) - , FilePermissions(file_permissions) - , Rename(rename) + , FilePermissions(std::move(file_permissions)) + , Rename(std::move(rename)) , Programs(programs) , Optional(optional) { diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h index a680037..8266603 100644 --- a/Source/cmInstallFilesGenerator.h +++ b/Source/cmInstallFilesGenerator.h @@ -21,11 +21,11 @@ class cmInstallFilesGenerator : public cmInstallGenerator { public: cmInstallFilesGenerator(std::vector<std::string> const& files, - const char* dest, bool programs, - const char* file_permissions, + std::string const& dest, bool programs, + std::string file_permissions, std::vector<std::string> const& configurations, - const char* component, MessageLevel message, - bool exclude_from_all, const char* rename, + std::string const& component, MessageLevel message, + bool exclude_from_all, std::string rename, bool optional = false); ~cmInstallFilesGenerator() override; @@ -42,11 +42,11 @@ protected: std::vector<std::string> const& files); cmLocalGenerator* LocalGenerator; - std::vector<std::string> Files; - std::string FilePermissions; - std::string Rename; - bool Programs; - bool Optional; + std::vector<std::string> const Files; + std::string const FilePermissions; + std::string const Rename; + bool const Programs; + bool const Optional; }; #endif diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx index ec17361..0665895 100644 --- a/Source/cmInstallGenerator.cxx +++ b/Source/cmInstallGenerator.cxx @@ -3,16 +3,17 @@ #include "cmInstallGenerator.h" #include <ostream> +#include <utility> #include "cmMakefile.h" #include "cmSystemTools.h" cmInstallGenerator::cmInstallGenerator( - const char* destination, std::vector<std::string> const& configurations, - const char* component, MessageLevel message, bool exclude_from_all) + std::string destination, std::vector<std::string> const& configurations, + std::string component, MessageLevel message, bool exclude_from_all) : cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations) - , Destination(destination ? destination : "") - , Component(component ? component : "") + , Destination(std::move(destination)) + , Component(std::move(component)) , Message(message) , ExcludeFromAll(exclude_from_all) { @@ -139,8 +140,8 @@ void cmInstallGenerator::AddInstallRule( os << ")\n"; } -std::string cmInstallGenerator::CreateComponentTest(const char* component, - bool exclude_from_all) +std::string cmInstallGenerator::CreateComponentTest( + const std::string& component, bool exclude_from_all) { std::string result = R"("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "x)"; result += component; @@ -158,7 +159,7 @@ void cmInstallGenerator::GenerateScript(std::ostream& os) // Begin this block of installation. std::string component_test = - this->CreateComponentTest(this->Component.c_str(), this->ExcludeFromAll); + this->CreateComponentTest(this->Component, this->ExcludeFromAll); os << indent << "if(" << component_test << ")\n"; // Generate the script possibly with per-configuration code. diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h index 024027d..d786d24 100644 --- a/Source/cmInstallGenerator.h +++ b/Source/cmInstallGenerator.h @@ -30,9 +30,9 @@ public: MessageNever }; - cmInstallGenerator(const char* destination, + cmInstallGenerator(std::string destination, std::vector<std::string> const& configurations, - const char* component, MessageLevel message, + std::string component, MessageLevel message, bool exclude_from_all); ~cmInstallGenerator() override; @@ -65,14 +65,14 @@ public: protected: void GenerateScript(std::ostream& os) override; - std::string CreateComponentTest(const char* component, + std::string CreateComponentTest(const std::string& component, bool exclude_from_all); // Information shared by most generator types. - std::string Destination; - std::string Component; - MessageLevel Message; - bool ExcludeFromAll; + std::string const Destination; + std::string const Component; + MessageLevel const Message; + bool const ExcludeFromAll; }; #endif diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx index 6bb4409..be07fd4 100644 --- a/Source/cmInstallProgramsCommand.cxx +++ b/Source/cmInstallProgramsCommand.cxx @@ -2,15 +2,20 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmInstallProgramsCommand.h" +#include <cm/memory> + #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" #include "cmInstallFilesGenerator.h" #include "cmInstallGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +class cmListFileBacktrace; + static void FinalAction(cmMakefile& makefile, std::string const& dest, std::vector<std::string> const& args); static std::string FindInstallSource(cmMakefile& makefile, const char* name); @@ -33,9 +38,10 @@ bool cmInstallProgramsCommand(std::vector<std::string> const& args, std::string const& dest = args[0]; std::vector<std::string> const finalArgs(args.begin() + 1, args.end()); - mf.AddFinalAction([dest, finalArgs](cmMakefile& makefile) { - FinalAction(makefile, dest, finalArgs); - }); + mf.AddGeneratorAction( + [dest, finalArgs](cmLocalGenerator& lg, const cmListFileBacktrace&) { + FinalAction(*lg.GetMakefile(), dest, finalArgs); + }); return true; } @@ -83,17 +89,17 @@ static void FinalAction(cmMakefile& makefile, std::string const& dest, } // Use a file install generator. - const char* no_permissions = ""; - const char* no_rename = ""; + const std::string no_permissions; + const std::string no_rename; bool no_exclude_from_all = false; std::string no_component = makefile.GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME"); std::vector<std::string> no_configurations; cmInstallGenerator::MessageLevel message = cmInstallGenerator::SelectMessageLevel(&makefile); - makefile.AddInstallGenerator(new cmInstallFilesGenerator( - files, destination.c_str(), true, no_permissions, no_configurations, - no_component.c_str(), message, no_exclude_from_all, no_rename)); + makefile.AddInstallGenerator(cm::make_unique<cmInstallFilesGenerator>( + files, destination, true, no_permissions, no_configurations, no_component, + message, no_exclude_from_all, no_rename)); } /** diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx index ea29455..7cdf3b4 100644 --- a/Source/cmInstallScriptGenerator.cxx +++ b/Source/cmInstallScriptGenerator.cxx @@ -3,6 +3,7 @@ #include "cmInstallScriptGenerator.h" #include <ostream> +#include <utility> #include <vector> #include "cmGeneratorExpression.h" @@ -11,13 +12,12 @@ #include "cmPolicies.h" #include "cmScriptGenerator.h" -cmInstallScriptGenerator::cmInstallScriptGenerator(const char* script, - bool code, - const char* component, - bool exclude_from_all) - : cmInstallGenerator(nullptr, std::vector<std::string>(), component, +cmInstallScriptGenerator::cmInstallScriptGenerator( + std::string script, bool code, std::string const& component, + bool exclude_from_all) + : cmInstallGenerator("", std::vector<std::string>(), component, MessageDefault, exclude_from_all) - , Script(script) + , Script(std::move(script)) , Code(code) , AllowGenex(false) { diff --git a/Source/cmInstallScriptGenerator.h b/Source/cmInstallScriptGenerator.h index 7efa321..0a9c4ba 100644 --- a/Source/cmInstallScriptGenerator.h +++ b/Source/cmInstallScriptGenerator.h @@ -19,8 +19,9 @@ class cmLocalGenerator; class cmInstallScriptGenerator : public cmInstallGenerator { public: - cmInstallScriptGenerator(const char* script, bool code, - const char* component, bool exclude_from_all); + cmInstallScriptGenerator(std::string script, bool code, + std::string const& component, + bool exclude_from_all); ~cmInstallScriptGenerator() override; bool Compute(cmLocalGenerator* lg) override; @@ -32,8 +33,8 @@ protected: void AddScriptInstallRule(std::ostream& os, Indent indent, std::string const& script); - std::string Script; - bool Code; + std::string const Script; + bool const Code; cmLocalGenerator* LocalGenerator; bool AllowGenex; }; diff --git a/Source/cmInstallSubdirectoryGenerator.cxx b/Source/cmInstallSubdirectoryGenerator.cxx index 8a0fefa..12bc92b 100644 --- a/Source/cmInstallSubdirectoryGenerator.cxx +++ b/Source/cmInstallSubdirectoryGenerator.cxx @@ -2,7 +2,9 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmInstallSubdirectoryGenerator.h" +#include <memory> #include <sstream> +#include <utility> #include <vector> #include "cmLocalGenerator.h" @@ -12,11 +14,11 @@ #include "cmSystemTools.h" cmInstallSubdirectoryGenerator::cmInstallSubdirectoryGenerator( - cmMakefile* makefile, const char* binaryDirectory, bool excludeFromAll) - : cmInstallGenerator(nullptr, std::vector<std::string>(), nullptr, - MessageDefault, excludeFromAll) + cmMakefile* makefile, std::string binaryDirectory, bool excludeFromAll) + : cmInstallGenerator("", std::vector<std::string>(), "", MessageDefault, + excludeFromAll) , Makefile(makefile) - , BinaryDirectory(binaryDirectory) + , BinaryDirectory(std::move(binaryDirectory)) { } @@ -24,7 +26,7 @@ cmInstallSubdirectoryGenerator::~cmInstallSubdirectoryGenerator() = default; bool cmInstallSubdirectoryGenerator::HaveInstall() { - for (auto generator : this->Makefile->GetInstallGenerators()) { + for (const auto& generator : this->Makefile->GetInstallGenerators()) { if (generator->HaveInstall()) { return true; } diff --git a/Source/cmInstallSubdirectoryGenerator.h b/Source/cmInstallSubdirectoryGenerator.h index b99bdd5..f9cd0f1 100644 --- a/Source/cmInstallSubdirectoryGenerator.h +++ b/Source/cmInstallSubdirectoryGenerator.h @@ -20,7 +20,7 @@ class cmInstallSubdirectoryGenerator : public cmInstallGenerator { public: cmInstallSubdirectoryGenerator(cmMakefile* makefile, - const char* binaryDirectory, + std::string binaryDirectory, bool excludeFromAll); ~cmInstallSubdirectoryGenerator() override; @@ -33,8 +33,8 @@ public: protected: void GenerateScript(std::ostream& os) override; - cmMakefile* Makefile; - std::string BinaryDirectory; + cmMakefile* const Makefile; + std::string const BinaryDirectory; cmLocalGenerator* LocalGenerator; }; diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index aa92fa7..e05daa8 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -25,15 +25,15 @@ #include "cmake.h" cmInstallTargetGenerator::cmInstallTargetGenerator( - std::string targetName, const char* dest, bool implib, - const char* file_permissions, std::vector<std::string> const& configurations, - const char* component, MessageLevel message, bool exclude_from_all, + std::string targetName, std::string const& dest, bool implib, + std::string file_permissions, std::vector<std::string> const& configurations, + std::string const& component, MessageLevel message, bool exclude_from_all, bool optional, cmListFileBacktrace backtrace) : cmInstallGenerator(dest, configurations, component, message, exclude_from_all) , TargetName(std::move(targetName)) , Target(nullptr) - , FilePermissions(file_permissions) + , FilePermissions(std::move(file_permissions)) , ImportLibrary(implib) , Optional(optional) , Backtrace(std::move(backtrace)) @@ -554,7 +554,8 @@ void cmInstallTargetGenerator::AddInstallNamePatchRule( // components of the install_name field then we need to create a // mapping to be applied after installation. std::string for_build = tgt->GetInstallNameDirForBuildTree(config); - std::string for_install = tgt->GetInstallNameDirForInstallTree(); + std::string for_install = tgt->GetInstallNameDirForInstallTree( + config, "${CMAKE_INSTALL_PREFIX}"); if (for_build != for_install) { // The directory portions differ. Append the filename to // create the mapping. @@ -577,7 +578,8 @@ void cmInstallTargetGenerator::AddInstallNamePatchRule( if (this->Target->GetType() == cmStateEnums::SHARED_LIBRARY) { std::string for_build = this->Target->GetInstallNameDirForBuildTree(config); - std::string for_install = this->Target->GetInstallNameDirForInstallTree(); + std::string for_install = this->Target->GetInstallNameDirForInstallTree( + config, "${CMAKE_INSTALL_PREFIX}"); if (this->Target->IsFrameworkOnApple() && for_install.empty()) { // Frameworks seem to have an id corresponding to their own full diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index 8730454..e21001f 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -23,11 +23,11 @@ class cmInstallTargetGenerator : public cmInstallGenerator { public: cmInstallTargetGenerator( - std::string targetName, const char* dest, bool implib, - const char* file_permissions, - std::vector<std::string> const& configurations, const char* component, - MessageLevel message, bool exclude_from_all, bool optional, - cmListFileBacktrace backtrace = cmListFileBacktrace()); + std::string targetName, std::string const& dest, bool implib, + std::string file_permissions, + std::vector<std::string> const& configurations, + std::string const& component, MessageLevel message, bool exclude_from_all, + bool optional, cmListFileBacktrace backtrace = cmListFileBacktrace()); ~cmInstallTargetGenerator() override; /** Select the policy for installing shared library linkable name @@ -106,13 +106,13 @@ protected: const std::string& toDestDirPath); void IssueCMP0095Warning(const std::string& unescapedRpath); - std::string TargetName; + std::string const TargetName; cmGeneratorTarget* Target; - std::string FilePermissions; + std::string const FilePermissions; NamelinkModeType NamelinkMode; - bool ImportLibrary; - bool Optional; - cmListFileBacktrace Backtrace; + bool const ImportLibrary; + bool const Optional; + cmListFileBacktrace const Backtrace; }; #endif diff --git a/Source/cmInstalledFile.cxx b/Source/cmInstalledFile.cxx index eabe590..32395d1 100644 --- a/Source/cmInstalledFile.cxx +++ b/Source/cmInstalledFile.cxx @@ -4,7 +4,6 @@ #include <utility> -#include "cmAlgorithms.h" #include "cmGeneratorExpression.h" #include "cmListFileCache.h" #include "cmMakefile.h" @@ -12,17 +11,11 @@ cmInstalledFile::cmInstalledFile() = default; -cmInstalledFile::~cmInstalledFile() -{ - delete NameExpression; -} +cmInstalledFile::~cmInstalledFile() = default; cmInstalledFile::Property::Property() = default; -cmInstalledFile::Property::~Property() -{ - cmDeleteAll(this->ValueExpressions); -} +cmInstalledFile::Property::~Property() = default; void cmInstalledFile::SetName(cmMakefile* mf, const std::string& name) { @@ -30,7 +23,7 @@ void cmInstalledFile::SetName(cmMakefile* mf, const std::string& name) cmGeneratorExpression ge(backtrace); this->Name = name; - this->NameExpression = ge.Parse(name).release(); + this->NameExpression = ge.Parse(name); } std::string const& cmInstalledFile::GetName() const @@ -49,7 +42,8 @@ void cmInstalledFile::RemoveProperty(const std::string& prop) } void cmInstalledFile::SetProperty(cmMakefile const* mf, - const std::string& prop, const char* value) + const std::string& prop, + const std::string& value) { this->RemoveProperty(prop); this->AppendProperty(mf, prop, value); @@ -57,13 +51,14 @@ void cmInstalledFile::SetProperty(cmMakefile const* mf, void cmInstalledFile::AppendProperty(cmMakefile const* mf, const std::string& prop, - const char* value, bool /*asString*/) + const std::string& value, + bool /*asString*/) { cmListFileBacktrace backtrace = mf->GetBacktrace(); cmGeneratorExpression ge(backtrace); Property& property = this->Properties[prop]; - property.ValueExpressions.push_back(ge.Parse(value).release()); + property.ValueExpressions.push_back(ge.Parse(value)); } bool cmInstalledFile::HasProperty(const std::string& prop) const @@ -84,7 +79,7 @@ bool cmInstalledFile::GetProperty(const std::string& prop, std::string output; std::string separator; - for (auto ve : property.ValueExpressions) { + for (const auto& ve : property.ValueExpressions) { output += separator; output += ve->GetInput(); separator = ";"; diff --git a/Source/cmInstalledFile.h b/Source/cmInstalledFile.h index ee809ee..07f7081 100644 --- a/Source/cmInstalledFile.h +++ b/Source/cmInstalledFile.h @@ -24,7 +24,7 @@ public: using CompiledGeneratorExpressionPtrType = std::unique_ptr<cmCompiledGeneratorExpression>; - using ExpressionVectorType = std::vector<cmCompiledGeneratorExpression*>; + using ExpressionVectorType = std::vector<CompiledGeneratorExpressionPtrType>; struct Property { @@ -49,10 +49,10 @@ public: void RemoveProperty(const std::string& prop); void SetProperty(cmMakefile const* mf, const std::string& prop, - const char* value); + const std::string& value); void AppendProperty(cmMakefile const* mf, const std::string& prop, - const char* value, bool asString = false); + const std::string& value, bool asString = false); bool HasProperty(const std::string& prop) const; @@ -73,7 +73,7 @@ public: private: std::string Name; - cmCompiledGeneratorExpression* NameExpression = nullptr; + CompiledGeneratorExpressionPtrType NameExpression; PropertyMapType Properties; }; diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx index b23ab43..dd36386 100644 --- a/Source/cmJsonObjects.cxx +++ b/Source/cmJsonObjects.cxx @@ -8,13 +8,15 @@ #include <functional> #include <limits> #include <map> +#include <memory> #include <set> #include <string> #include <unordered_map> #include <utility> #include <vector> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" @@ -43,7 +45,7 @@ namespace { std::vector<std::string> getConfigurations(const cmake* cm) { std::vector<std::string> configurations; - auto makefiles = cm->GetGlobalGenerator()->GetMakefiles(); + const auto& makefiles = cm->GetGlobalGenerator()->GetMakefiles(); if (makefiles.empty()) { return configurations; } @@ -82,8 +84,8 @@ void cmGetCMakeInputs(const cmGlobalGenerator* gg, std::vector<std::string>* tmpFiles) { const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/'; - std::vector<cmMakefile*> const& makefiles = gg->GetMakefiles(); - for (cmMakefile const* mf : makefiles) { + auto const& makefiles = gg->GetMakefiles(); + for (const auto& mf : makefiles) { for (std::string const& lf : mf->GetListFiles()) { const std::string startOfFile = lf.substr(0, cmakeRootDir.size()); @@ -485,10 +487,10 @@ static Json::Value DumpTarget(cmGeneratorTarget* target, result[kHAS_INSTALL_RULE] = true; Json::Value installPaths = Json::arrayValue; - auto targetGenerators = target->Makefile->GetInstallGenerators(); - for (auto installGenerator : targetGenerators) { + for (const auto& installGenerator : + target->Makefile->GetInstallGenerators()) { auto installTargetGenerator = - dynamic_cast<cmInstallTargetGenerator*>(installGenerator); + dynamic_cast<cmInstallTargetGenerator*>(installGenerator.get()); if (installTargetGenerator != nullptr && installTargetGenerator->GetTarget()->Target == target->Target) { auto dest = installTargetGenerator->GetDestination(config); @@ -601,7 +603,7 @@ static Json::Value DumpTargetsList( std::vector<cmGeneratorTarget*> targetList; for (auto const& lgIt : generators) { - cmAppend(targetList, lgIt->GetGeneratorTargets()); + cm::append(targetList, lgIt->GetGeneratorTargets()); } std::sort(targetList.begin(), targetList.end()); @@ -641,9 +643,9 @@ static Json::Value DumpProjectList(const cmake* cm, std::string const& config) // associated generators. bool hasInstallRule = false; for (const auto generator : projectIt.second) { - for (const auto installGen : + for (const auto& installGen : generator->GetMakefile()->GetInstallGenerators()) { - if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(installGen)) { + if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(installGen.get())) { hasInstallRule = true; break; } diff --git a/Source/cmLinkItem.cxx b/Source/cmLinkItem.cxx index 91eb183..4e50d70 100644 --- a/Source/cmLinkItem.cxx +++ b/Source/cmLinkItem.cxx @@ -8,14 +8,17 @@ cmLinkItem::cmLinkItem() = default; -cmLinkItem::cmLinkItem(std::string n, cmListFileBacktrace bt) +cmLinkItem::cmLinkItem(std::string n, bool c, cmListFileBacktrace bt) : String(std::move(n)) + , Cross(c) , Backtrace(std::move(bt)) { } -cmLinkItem::cmLinkItem(cmGeneratorTarget const* t, cmListFileBacktrace bt) +cmLinkItem::cmLinkItem(cmGeneratorTarget const* t, bool c, + cmListFileBacktrace bt) : Target(t) + , Cross(c) , Backtrace(std::move(bt)) { } @@ -39,12 +42,16 @@ bool operator<(cmLinkItem const& l, cmLinkItem const& r) return false; } // Order among strings. - return l.String < r.String; + if (l.String < r.String) { + return true; + } + // Order among cross-config. + return l.Cross < r.Cross; } bool operator==(cmLinkItem const& l, cmLinkItem const& r) { - return l.Target == r.Target && l.String == r.String; + return l.Target == r.Target && l.String == r.String && l.Cross == r.Cross; } std::ostream& operator<<(std::ostream& os, cmLinkItem const& item) diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h index 2d9378b..ae87e45 100644 --- a/Source/cmLinkItem.h +++ b/Source/cmLinkItem.h @@ -24,10 +24,11 @@ class cmLinkItem public: cmLinkItem(); - cmLinkItem(std::string s, cmListFileBacktrace bt); - cmLinkItem(cmGeneratorTarget const* t, cmListFileBacktrace bt); + cmLinkItem(std::string s, bool c, cmListFileBacktrace bt); + cmLinkItem(cmGeneratorTarget const* t, bool c, cmListFileBacktrace bt); std::string const& AsStr() const; cmGeneratorTarget const* Target = nullptr; + bool Cross = false; cmListFileBacktrace Backtrace; friend bool operator<(cmLinkItem const& l, cmLinkItem const& r); friend bool operator==(cmLinkItem const& l, cmLinkItem const& r); @@ -80,6 +81,9 @@ struct cmLinkInterface : public cmLinkInterfaceLibraries std::vector<cmLinkItem> WrongConfigLibraries; bool ImplementationIsInterface = false; + + // Whether the list depends on a link language genex. + bool HadLinkLanguageSensitiveCondition = false; }; struct cmOptionalLinkInterface : public cmLinkInterface @@ -99,6 +103,9 @@ struct cmLinkImplementation : public cmLinkImplementationLibraries { // Languages whose runtime libraries must be linked. std::vector<std::string> Languages; + + // Whether the list depends on a link language genex. + bool HadLinkLanguageSensitiveCondition = false; }; // Cache link implementation computation from each configuration. diff --git a/Source/cmLinkItemGraphVisitor.cxx b/Source/cmLinkItemGraphVisitor.cxx new file mode 100644 index 0000000..acc23c8 --- /dev/null +++ b/Source/cmLinkItemGraphVisitor.cxx @@ -0,0 +1,142 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmLinkItemGraphVisitor.h" + +#include <map> +#include <utility> +#include <vector> + +#include "cmGeneratorTarget.h" +#include "cmLinkItem.h" +#include "cmMakefile.h" + +void cmLinkItemGraphVisitor::VisitItem(cmLinkItem const& item) +{ + if (this->ItemVisited(item)) { + return; + } + + this->OnItem(item); + + this->VisitLinks(item, item); +} + +void cmLinkItemGraphVisitor::VisitLinks(cmLinkItem const& item, + cmLinkItem const& rootItem) +{ + if (this->LinkVisited(item, rootItem)) { + return; + } + + if (item.Target == nullptr) { + return; + } + + for (auto const& config : item.Target->Makefile->GetGeneratorConfigs()) { + this->VisitLinks(item, rootItem, config); + } +} + +void cmLinkItemGraphVisitor::VisitLinks(cmLinkItem const& item, + cmLinkItem const& rootItem, + std::string const& config) +{ + auto const& target = *item.Target; + + DependencyMap dependencies; + cmLinkItemGraphVisitor::GetDependencies(target, config, dependencies); + + for (auto const& d : dependencies) { + auto const& dependency = d.second; + auto const& dependencyType = dependency.first; + auto const& dependee = dependency.second; + this->VisitItem(dependee); + + if (this->LinkVisited(item, dependee)) { + continue; + } + + this->OnDirectLink(item, dependee, dependencyType); + + if (rootItem.AsStr() != item.AsStr()) { + this->OnIndirectLink(rootItem, dependee); + } + + // Visit all the direct and indirect links. + this->VisitLinks(dependee, dependee); + this->VisitLinks(dependee, item); + this->VisitLinks(dependee, rootItem); + } +} + +bool cmLinkItemGraphVisitor::ItemVisited(cmLinkItem const& item) +{ + auto& collection = this->VisitedItems; + + bool const visited = collection.find(item.AsStr()) != collection.cend(); + + if (!visited) { + collection.insert(item.AsStr()); + } + + return visited; +} + +bool cmLinkItemGraphVisitor::LinkVisited(cmLinkItem const& depender, + cmLinkItem const& dependee) +{ + auto const link = std::make_pair<>(depender.AsStr(), dependee.AsStr()); + + bool const linkVisited = + this->VisitedLinks.find(link) != this->VisitedLinks.cend(); + + if (!linkVisited) { + this->VisitedLinks.insert(link); + } + + return linkVisited; +} + +void cmLinkItemGraphVisitor::GetDependencies(cmGeneratorTarget const& target, + std::string const& config, + DependencyMap& dependencies) +{ + auto implementationLibraries = target.GetLinkImplementationLibraries(config); + if (implementationLibraries != nullptr) { + for (auto const& lib : implementationLibraries->Libraries) { + auto const& name = lib.AsStr(); + dependencies[name] = Dependency(DependencyType::LinkPrivate, lib); + } + } + + auto interfaceLibraries = + target.GetLinkInterfaceLibraries(config, &target, true); + if (interfaceLibraries != nullptr) { + for (auto const& lib : interfaceLibraries->Libraries) { + auto const& name = lib.AsStr(); + if (dependencies.find(name) != dependencies.cend()) { + dependencies[name] = Dependency(DependencyType::LinkPublic, lib); + } else { + dependencies[name] = Dependency(DependencyType::LinkInterface, lib); + } + } + } + + std::vector<cmGeneratorTarget*> objectLibraries; + target.GetObjectLibrariesCMP0026(objectLibraries); + for (auto const& lib : objectLibraries) { + auto const& name = lib->GetName(); + if (dependencies.find(name) == dependencies.cend()) { + auto objectItem = cmLinkItem(lib, false, lib->GetBacktrace()); + dependencies[name] = Dependency(DependencyType::Object, objectItem); + } + } + + auto const& utilityItems = target.GetUtilityItems(); + for (auto const& item : utilityItems) { + auto const& name = item.AsStr(); + if (dependencies.find(name) == dependencies.cend()) { + dependencies[name] = Dependency(DependencyType::Utility, item); + } + } +} diff --git a/Source/cmLinkItemGraphVisitor.h b/Source/cmLinkItemGraphVisitor.h new file mode 100644 index 0000000..21dc659 --- /dev/null +++ b/Source/cmLinkItemGraphVisitor.h @@ -0,0 +1,75 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmLinkItemGraphVisitor_h +#define cmLinkItemGraphVisitor_h + +#include <map> +#include <set> +#include <string> +#include <utility> + +#include "cmLinkItem.h" + +class cmGeneratorTarget; + +/** \class cmLinkItemGraphVisitor + * \brief Visits a graph of linked items. + * + * Allows to visit items and dependency links (direct and indirect) between + * those items. + * This abstract class takes care of the graph traversal, making sure that: + * - it terminates even in the presence of cycles; + * - it visits every object once (and only once); + * - it visits the objects in the same order every time. + * + * Children classes only have to implement OnItem() etc. to handle whatever + * logic they care about. + */ +class cmLinkItemGraphVisitor +{ +public: + virtual ~cmLinkItemGraphVisitor() = default; + + virtual void VisitGraph(std::string const& name) = 0; + + void VisitItem(cmLinkItem const& item); + +protected: + enum class DependencyType + { + LinkInterface, + LinkPublic, + LinkPrivate, + Object, + Utility + }; + + virtual void OnItem(cmLinkItem const& item) = 0; + + virtual void OnDirectLink(cmLinkItem const& depender, + cmLinkItem const& dependee, DependencyType dt) = 0; + + virtual void OnIndirectLink(cmLinkItem const& depender, + cmLinkItem const& dependee) = 0; + +private: + std::set<std::string> VisitedItems; + + std::set<std::pair<std::string, std::string>> VisitedLinks; + + void VisitLinks(cmLinkItem const& item, cmLinkItem const& rootItem); + void VisitLinks(cmLinkItem const& item, cmLinkItem const& rootItem, + std::string const& config); + + using Dependency = std::pair<DependencyType, cmLinkItem>; + using DependencyMap = std::map<std::string, Dependency>; + + bool ItemVisited(cmLinkItem const& item); + bool LinkVisited(cmLinkItem const& depender, cmLinkItem const& dependee); + + static void GetDependencies(cmGeneratorTarget const& target, + std::string const& config, + DependencyMap& dependencies); +}; + +#endif diff --git a/Source/cmLinkLibrariesCommand.cxx b/Source/cmLinkLibrariesCommand.cxx index cb63ceb..2b8f836 100644 --- a/Source/cmLinkLibrariesCommand.cxx +++ b/Source/cmLinkLibrariesCommand.cxx @@ -32,7 +32,7 @@ bool cmLinkLibrariesCommand(std::vector<std::string> const& args, } mf.AppendProperty("LINK_LIBRARIES", "optimized"); } - mf.AppendProperty("LINK_LIBRARIES", i->c_str()); + mf.AppendProperty("LINK_LIBRARIES", *i); } return true; diff --git a/Source/cmLinkLineComputer.cxx b/Source/cmLinkLineComputer.cxx index 3fc41cf..480c005 100644 --- a/Source/cmLinkLineComputer.cxx +++ b/Source/cmLinkLineComputer.cxx @@ -22,6 +22,7 @@ cmLinkLineComputer::cmLinkLineComputer(cmOutputConverter* outputConverter, , OutputConverter(outputConverter) , ForResponse(false) , UseWatcomQuote(false) + , UseNinjaMulti(false) , Relink(false) { } @@ -33,6 +34,11 @@ void cmLinkLineComputer::SetUseWatcomQuote(bool useWatcomQuote) this->UseWatcomQuote = useWatcomQuote; } +void cmLinkLineComputer::SetUseNinjaMulti(bool useNinjaMulti) +{ + this->UseNinjaMulti = useNinjaMulti; +} + void cmLinkLineComputer::SetForResponse(bool forResponse) { this->ForResponse = forResponse; @@ -92,10 +98,14 @@ void cmLinkLineComputer::ComputeLinkLibs( std::string cmLinkLineComputer::ConvertToOutputFormat(std::string const& input) { - cmOutputConverter::OutputFormat shellFormat = (this->ForResponse) - ? cmOutputConverter::RESPONSE - : ((this->UseWatcomQuote) ? cmOutputConverter::WATCOMQUOTE - : cmOutputConverter::SHELL); + cmOutputConverter::OutputFormat shellFormat = cmOutputConverter::SHELL; + if (this->ForResponse) { + shellFormat = cmOutputConverter::RESPONSE; + } else if (this->UseWatcomQuote) { + shellFormat = cmOutputConverter::WATCOMQUOTE; + } else if (this->UseNinjaMulti) { + shellFormat = cmOutputConverter::NINJAMULTI; + } return this->OutputConverter->ConvertToOutputFormat(input, shellFormat); } @@ -103,10 +113,14 @@ std::string cmLinkLineComputer::ConvertToOutputFormat(std::string const& input) std::string cmLinkLineComputer::ConvertToOutputForExisting( std::string const& input) { - cmOutputConverter::OutputFormat shellFormat = (this->ForResponse) - ? cmOutputConverter::RESPONSE - : ((this->UseWatcomQuote) ? cmOutputConverter::WATCOMQUOTE - : cmOutputConverter::SHELL); + cmOutputConverter::OutputFormat shellFormat = cmOutputConverter::SHELL; + if (this->ForResponse) { + shellFormat = cmOutputConverter::RESPONSE; + } else if (this->UseWatcomQuote) { + shellFormat = cmOutputConverter::WATCOMQUOTE; + } else if (this->UseNinjaMulti) { + shellFormat = cmOutputConverter::NINJAMULTI; + } return this->OutputConverter->ConvertToOutputForExisting(input, shellFormat); } diff --git a/Source/cmLinkLineComputer.h b/Source/cmLinkLineComputer.h index f426976..df42468 100644 --- a/Source/cmLinkLineComputer.h +++ b/Source/cmLinkLineComputer.h @@ -28,6 +28,7 @@ public: cmLinkLineComputer& operator=(cmLinkLineComputer const&) = delete; void SetUseWatcomQuote(bool useWatcomQuote); + void SetUseNinjaMulti(bool useNinjaMulti); void SetForResponse(bool forResponse); void SetRelink(bool relink); @@ -69,6 +70,7 @@ protected: bool ForResponse; bool UseWatcomQuote; + bool UseNinjaMulti; bool Relink; }; diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 47679c9..7ebb02f 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -26,13 +26,15 @@ cmCommandContext::cmCommandName& cmCommandContext::cmCommandName::operator=( struct cmListFileParser { cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, - cmMessenger* messenger, const char* filename); + cmMessenger* messenger); ~cmListFileParser(); cmListFileParser(const cmListFileParser&) = delete; cmListFileParser& operator=(const cmListFileParser&) = delete; void IssueFileOpenError(std::string const& text) const; void IssueError(std::string const& text) const; - bool ParseFile(); + bool ParseFile(const char* filename); + bool ParseString(const char* str, const char* virtual_filename); + bool Parse(); bool ParseFunction(const char* name, long line); bool AddArgument(cmListFileLexer_Token* token, cmListFileArgument::Delimiter delim); @@ -51,12 +53,11 @@ struct cmListFileParser }; cmListFileParser::cmListFileParser(cmListFile* lf, cmListFileBacktrace lfbt, - cmMessenger* messenger, - const char* filename) + cmMessenger* messenger) : ListFile(lf) , Backtrace(std::move(lfbt)) , Messenger(messenger) - , FileName(filename) + , FileName(nullptr) , Lexer(cmListFileLexer_New()) { } @@ -83,8 +84,10 @@ void cmListFileParser::IssueError(const std::string& text) const cmSystemTools::SetFatalErrorOccured(); } -bool cmListFileParser::ParseFile() +bool cmListFileParser::ParseFile(const char* filename) { + this->FileName = filename; + // Open the file. cmListFileLexer_BOM bom; if (!cmListFileLexer_SetFileName(this->Lexer, this->FileName, &bom)) { @@ -107,6 +110,24 @@ bool cmListFileParser::ParseFile() return false; } + return Parse(); +} + +bool cmListFileParser::ParseString(const char* str, + const char* virtual_filename) +{ + this->FileName = virtual_filename; + + if (!cmListFileLexer_SetString(this->Lexer, str)) { + this->IssueFileOpenError("cmListFileCache: cannot allocate buffer."); + return false; + } + + return Parse(); +} + +bool cmListFileParser::Parse() +{ // Use a simple recursive-descent parser to process the token // stream. bool haveNewline = true; @@ -155,8 +176,22 @@ bool cmListFile::ParseFile(const char* filename, cmMessenger* messenger, bool parseError = false; { - cmListFileParser parser(this, lfbt, messenger, filename); - parseError = !parser.ParseFile(); + cmListFileParser parser(this, lfbt, messenger); + parseError = !parser.ParseFile(filename); + } + + return !parseError; +} + +bool cmListFile::ParseString(const char* str, const char* virtual_filename, + cmMessenger* messenger, + const cmListFileBacktrace& lfbt) +{ + bool parseError = false; + + { + cmListFileParser parser(this, lfbt, messenger); + parseError = !parser.ParseString(str, virtual_filename); } return !parseError; diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index 9cae827..89902ff 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -184,6 +184,9 @@ struct cmListFile bool ParseFile(const char* path, cmMessenger* messenger, cmListFileBacktrace const& lfbt); + bool ParseString(const char* str, const char* virtual_filename, + cmMessenger* messenger, cmListFileBacktrace const& lfbt); + std::vector<cmListFileFunction> Functions; }; diff --git a/Source/cmLoadCacheCommand.cxx b/Source/cmLoadCacheCommand.cxx index 1184bcb..d49e711 100644 --- a/Source/cmLoadCacheCommand.cxx +++ b/Source/cmLoadCacheCommand.cxx @@ -24,12 +24,20 @@ bool cmLoadCacheCommand(std::vector<std::string> const& args, { if (args.empty()) { status.SetError("called with wrong number of arguments."); + return false; } if (args.size() >= 2 && args[1] == "READ_WITH_PREFIX") { return ReadWithPrefix(args, status); } + if (status.GetMakefile().GetCMakeInstance()->GetWorkingMode() == + cmake::SCRIPT_MODE) { + status.SetError( + "Only load_cache(READ_WITH_PREFIX) may be used in script mode"); + return false; + } + // Cache entries to be excluded from the import list. // If this set is empty, all cache entries are brought in // and they can not be overridden. diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx index 23ace64..92258e2 100644 --- a/Source/cmLoadCommandCommand.cxx +++ b/Source/cmLoadCommandCommand.cxx @@ -14,6 +14,7 @@ #include "cmCommand.h" #include "cmDynamicLoader.h" #include "cmExecutionStatus.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -25,6 +26,8 @@ # include <malloc.h> /* for malloc/free on QNX */ #endif +class cmListFileBacktrace; + namespace { const char* LastName = nullptr; @@ -158,8 +161,10 @@ bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args, if (result) { if (this->Impl->FinalPass) { auto impl = this->Impl; - this->Makefile->AddFinalAction( - [impl](cmMakefile& makefile) { impl->DoFinalPass(&makefile); }); + this->Makefile->AddGeneratorAction( + [impl](cmLocalGenerator& lg, const cmListFileBacktrace&) { + impl->DoFinalPass(lg.GetMakefile()); + }); } return true; } diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx index f86955d..278ec8b 100644 --- a/Source/cmLocalCommonGenerator.cxx +++ b/Source/cmLocalCommonGenerator.cxx @@ -17,13 +17,9 @@ cmLocalCommonGenerator::cmLocalCommonGenerator(cmGlobalGenerator* gg, : cmLocalGenerator(gg, mf) , WorkingDirectory(std::move(wd)) { - // Store the configuration name that will be generated. - if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) { - // Use the build type given by the user. - this->ConfigName = config; - } else { - // No configuration type given. - this->ConfigName.clear(); + this->Makefile->GetConfigurations(this->ConfigNames); + if (this->ConfigNames.empty()) { + this->ConfigNames.emplace_back(); } } @@ -54,6 +50,15 @@ std::string cmLocalCommonGenerator::GetTargetFortranFlags( this->Makefile->GetRequiredDefinition("CMAKE_Fortran_MODDIR_FLAG"), mod_dir); this->AppendFlags(flags, modflag); + // Some compilers do not search their own module output directory + // for using other modules. Add an include directory explicitly + // for consistency with compilers that do search it. + std::string incflag = + this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODDIR_INCLUDE_FLAG"); + if (!incflag.empty()) { + incflag = cmStrCat(incflag, mod_dir); + this->AppendFlags(flags, incflag); + } } // If there is a separate module path flag then duplicate the diff --git a/Source/cmLocalCommonGenerator.h b/Source/cmLocalCommonGenerator.h index eaef6ab..378ca63 100644 --- a/Source/cmLocalCommonGenerator.h +++ b/Source/cmLocalCommonGenerator.h @@ -7,6 +7,7 @@ #include <map> #include <string> +#include <vector> #include "cmLocalGenerator.h" @@ -25,7 +26,10 @@ public: std::string wd); ~cmLocalCommonGenerator() override; - std::string const& GetConfigName() const { return this->ConfigName; } + std::vector<std::string> const& GetConfigNames() const + { + return this->ConfigNames; + } std::string GetWorkingDirectory() const { return this->WorkingDirectory; } @@ -39,7 +43,7 @@ public: protected: std::string WorkingDirectory; - std::string ConfigName; + std::vector<std::string> ConfigNames; friend class cmCommonTargetGenerator; }; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index ffd46d4..a7799b6 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2,6 +2,22 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmLocalGenerator.h" +#include <algorithm> +#include <cassert> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <initializer_list> +#include <iterator> +#include <sstream> +#include <unordered_set> +#include <utility> +#include <vector> + +#include <cm/memory> +#include <cm/string_view> +#include <cmext/algorithm> + #include "cmsys/RegularExpression.hxx" #include "cmAlgorithms.h" @@ -40,20 +56,6 @@ # include "cmCryptoHash.h" #endif -#include <algorithm> -#include <cassert> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <initializer_list> -#include <iterator> -#include <sstream> -#include <unordered_set> -#include <utility> -#include <vector> - -#include <cm/string_view> - #if defined(__HAIKU__) # include <FindDirectory.h> # include <StorageDefs.h> @@ -181,11 +183,7 @@ cmRulePlaceholderExpander* cmLocalGenerator::CreateRulePlaceholderExpander() this->LinkerSysroot); } -cmLocalGenerator::~cmLocalGenerator() -{ - cmDeleteAll(this->GeneratorTargets); - cmDeleteAll(this->OwnedImportedGeneratorTargets); -} +cmLocalGenerator::~cmLocalGenerator() = default; void cmLocalGenerator::IssueMessage(MessageType t, std::string const& text) const @@ -263,8 +261,8 @@ static void MoveSystemIncludesToEnd(std::vector<BT<std::string>>& includeDirs, void cmLocalGenerator::TraceDependencies() { // Generate the rule files for each target. - const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { + const auto& targets = this->GetGeneratorTargets(); + for (const auto& target : targets) { if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } @@ -317,9 +315,7 @@ void cmLocalGenerator::GenerateTestFiles() } // Ask each test generator to write its code. - std::vector<cmTestGenerator*> const& testers = - this->Makefile->GetTestGenerators(); - for (cmTestGenerator* tester : testers) { + for (const auto& tester : this->Makefile->GetTestGenerators()) { tester->Compute(this); tester->Generate(fout, config, configurationTypes); } @@ -365,9 +361,7 @@ void cmLocalGenerator::CreateEvaluationFileOutputs() void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config) { - std::vector<cmGeneratorExpressionEvaluationFile*> ef = - this->Makefile->GetEvaluationFiles(); - for (cmGeneratorExpressionEvaluationFile* geef : ef) { + for (const auto& geef : this->Makefile->GetEvaluationFiles()) { geef->CreateOutputFile(this, config); } } @@ -375,8 +369,7 @@ void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config) void cmLocalGenerator::ProcessEvaluationFiles( std::vector<std::string>& generatedFiles) { - for (cmGeneratorExpressionEvaluationFile* geef : - this->Makefile->GetEvaluationFiles()) { + for (const auto& geef : this->Makefile->GetEvaluationFiles()) { geef->Generate(this); if (cmSystemTools::GetFatalErrorOccured()) { return; @@ -395,7 +388,7 @@ void cmLocalGenerator::ProcessEvaluationFiles( return; } - cmAppend(generatedFiles, files); + cm::append(generatedFiles, files); std::inplace_merge(generatedFiles.begin(), generatedFiles.end() - files.size(), generatedFiles.end()); @@ -559,18 +552,17 @@ void cmLocalGenerator::GenerateInstallRules() // Ask each install generator to write its code. cmPolicies::PolicyStatus status = this->GetPolicyStatus(cmPolicies::CMP0082); - std::vector<cmInstallGenerator*> const& installers = - this->Makefile->GetInstallGenerators(); + auto const& installers = this->Makefile->GetInstallGenerators(); bool haveSubdirectoryInstall = false; bool haveInstallAfterSubdirectory = false; if (status == cmPolicies::WARN) { - for (cmInstallGenerator* installer : installers) { + for (const auto& installer : installers) { installer->CheckCMP0082(haveSubdirectoryInstall, haveInstallAfterSubdirectory); installer->Generate(fout, config, configurationTypes); } } else { - for (cmInstallGenerator* installer : installers) { + for (const auto& installer : installers) { installer->Generate(fout, config, configurationTypes); } } @@ -635,11 +627,14 @@ void cmLocalGenerator::GenerateInstallRules() } } -void cmLocalGenerator::AddGeneratorTarget(cmGeneratorTarget* gt) +void cmLocalGenerator::AddGeneratorTarget( + std::unique_ptr<cmGeneratorTarget> gt) { - this->GeneratorTargets.push_back(gt); - this->GeneratorTargetSearchIndex.emplace(gt->GetName(), gt); - this->GlobalGenerator->IndexGeneratorTarget(gt); + cmGeneratorTarget* gt_ptr = gt.get(); + + this->GeneratorTargets.push_back(std::move(gt)); + this->GeneratorTargetSearchIndex.emplace(gt_ptr->GetName(), gt_ptr); + this->GlobalGenerator->IndexGeneratorTarget(gt_ptr); } void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt) @@ -648,9 +643,10 @@ void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt) this->GlobalGenerator->IndexGeneratorTarget(gt); } -void cmLocalGenerator::AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt) +void cmLocalGenerator::AddOwnedImportedGeneratorTarget( + std::unique_ptr<cmGeneratorTarget> gt) { - this->OwnedImportedGeneratorTargets.push_back(gt); + this->OwnedImportedGeneratorTargets.push_back(std::move(gt)); } cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget( @@ -673,8 +669,8 @@ void cmLocalGenerator::ComputeTargetManifest() } // Add our targets to the manifest for each configuration. - const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { + const auto& targets = this->GetGeneratorTargets(); + for (const auto& target : targets) { if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } @@ -695,17 +691,18 @@ bool cmLocalGenerator::ComputeTargetCompileFeatures() using LanguagePair = std::pair<std::string, std::string>; std::vector<LanguagePair> pairedLanguages{ { "OBJC", "C" }, - { "OBJCXX", "CXX" } }; - std::set<LanguagePair> objcEnabledLanguages; + { "OBJCXX", "CXX" }, + { "CUDA", "CXX" } }; + std::set<LanguagePair> inferredEnabledLanguages; for (auto const& lang : pairedLanguages) { if (this->Makefile->GetState()->GetLanguageEnabled(lang.first)) { - objcEnabledLanguages.insert(lang); + inferredEnabledLanguages.insert(lang); } } // Process compile features of all targets. - const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets(); - for (cmGeneratorTarget* target : targets) { + const auto& targets = this->GetGeneratorTargets(); + for (const auto& target : targets) { for (std::string const& c : configNames) { if (!target->ComputeCompileFeatures(c)) { return false; @@ -738,12 +735,17 @@ bool cmLocalGenerator::ComputeTargetCompileFeatures() target->GetProperty(cmStrCat(lang.second, property))); } }; - for (auto const& lang : objcEnabledLanguages) { + for (auto const& lang : pairedLanguages) { if (copyStandardToObjLang(lang)) { copyPropertyToObjLang(lang, "_STANDARD_REQUIRED"); copyPropertyToObjLang(lang, "_EXTENSIONS"); } } + if (const char* standard = target->GetProperty("CUDA_STANDARD")) { + if (std::string{ standard } == "98") { + target->Target->SetProperty("CUDA_STANDARD", "03"); + } + } } } @@ -988,6 +990,91 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, } } +cmTarget* cmLocalGenerator::AddCustomCommandToTarget( + const std::string& target, const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, + const cmCustomCommandLines& commandLines, cmCustomCommandType type, + const char* comment, const char* workingDir, bool escapeOldStyle, + bool uses_terminal, const std::string& depfile, const std::string& job_pool, + bool command_expand_lists, cmObjectLibraryCommands objLibCommands) +{ + cmTarget* t = this->Makefile->GetCustomCommandTarget( + target, objLibCommands, this->DirectoryBacktrace); + if (!t) { + return nullptr; + } + + detail::AddCustomCommandToTarget( + *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, t, byproducts, + depends, commandLines, type, comment, workingDir, escapeOldStyle, + uses_terminal, depfile, job_pool, command_expand_lists); + + return t; +} + +cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput( + const std::string& output, const std::vector<std::string>& depends, + const std::string& main_dependency, const cmCustomCommandLines& commandLines, + const char* comment, const char* workingDir, bool replace, + bool escapeOldStyle, bool uses_terminal, bool command_expand_lists, + const std::string& depfile, const std::string& job_pool) +{ + std::vector<std::string> no_byproducts; + cmImplicitDependsList no_implicit_depends; + return this->AddCustomCommandToOutput( + { output }, no_byproducts, depends, main_dependency, no_implicit_depends, + commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal, + command_expand_lists, depfile, job_pool); +} + +cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput( + const std::vector<std::string>& outputs, + const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, const std::string& main_dependency, + const cmImplicitDependsList& implicit_depends, + const cmCustomCommandLines& commandLines, const char* comment, + const char* workingDir, bool replace, bool escapeOldStyle, + bool uses_terminal, bool command_expand_lists, const std::string& depfile, + const std::string& job_pool) +{ + // Make sure there is at least one output. + if (outputs.empty()) { + cmSystemTools::Error("Attempt to add a custom rule with no output!"); + return nullptr; + } + + return detail::AddCustomCommandToOutput( + *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, outputs, + byproducts, depends, main_dependency, implicit_depends, commandLines, + comment, workingDir, replace, escapeOldStyle, uses_terminal, + command_expand_lists, depfile, job_pool); +} + +cmTarget* cmLocalGenerator::AddUtilityCommand( + const std::string& utilityName, bool excludeFromAll, const char* workingDir, + const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, + const cmCustomCommandLines& commandLines, bool escapeOldStyle, + const char* comment, bool uses_terminal, bool command_expand_lists, + const std::string& job_pool) +{ + cmTarget* target = + this->Makefile->AddNewUtilityTarget(utilityName, excludeFromAll); + target->SetIsGeneratorProvided(true); + + if (commandLines.empty() && depends.empty()) { + return target; + } + + detail::AddUtilityCommand( + *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, target, + this->Makefile->GetUtilityOutput(target), workingDir, byproducts, depends, + commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists, + job_pool); + + return target; +} + std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit( cmGeneratorTarget const* target, std::string const& lang, std::string const& config, bool stripImplicitDirs, @@ -1084,7 +1171,7 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit( } for (std::string const& i : impDirVec) { - if (implicitSet.insert(cmSystemTools::GetRealPath(i)).second) { + if (implicitSet.insert(this->GlobalGenerator->GetRealPath(i)).second) { implicitDirs.emplace_back(i); } } @@ -1095,7 +1182,7 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit( &lang](std::string const& dir) { return ( // Do not exclude directories that are not in an excluded set. - ((!cmContains(implicitSet, cmSystemTools::GetRealPath(dir))) && + ((!cmContains(implicitSet, this->GlobalGenerator->GetRealPath(dir))) && (!cmContains(implicitExclude, dir))) // Do not exclude entries of the CPATH environment variable even though // they are implicitly searched by the compiler. They are meant to be @@ -1685,10 +1772,18 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, const std::string& lang, const std::string& config) { - // Only add macOS specific flags on Darwin platforms (macOS and iOS): + // Only add Apple specific flags on Apple platforms if (this->Makefile->IsOn("APPLE") && this->EmitUniversalBinaryFlags) { std::vector<std::string> archs; target->GetAppleArchs(config, archs); + if (!archs.empty() && !lang.empty() && + (lang[0] == 'C' || lang[0] == 'F' || lang[0] == 'O')) { + for (std::string const& arch : archs) { + flags += " -arch "; + flags += arch; + } + } + const char* sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT"); if (sysroot && sysroot[0] == '/' && !sysroot[1]) { sysroot = nullptr; @@ -1696,27 +1791,37 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, std::string sysrootFlagVar = std::string("CMAKE_") + lang + "_SYSROOT_FLAG"; const char* sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar); + if (sysrootFlag && *sysrootFlag) { + std::vector<std::string> arch_sysroots; + if (const char* arch_sysroots_str = + this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) { + cmExpandList(std::string(arch_sysroots_str), arch_sysroots, true); + } + if (!arch_sysroots.empty()) { + assert(arch_sysroots.size() == archs.size()); + for (size_t i = 0; i < archs.size(); ++i) { + if (arch_sysroots[i].empty()) { + continue; + } + flags += " -Xarch_" + archs[i] + " "; + // Combine sysroot flag and path to work with -Xarch + std::string arch_sysroot = sysrootFlag + arch_sysroots[i]; + flags += this->ConvertToOutputFormat(arch_sysroot, SHELL); + } + } else if (sysroot && *sysroot) { + flags += " "; + flags += sysrootFlag; + flags += " "; + flags += this->ConvertToOutputFormat(sysroot, SHELL); + } + } + const char* deploymentTarget = this->Makefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET"); std::string deploymentTargetFlagVar = std::string("CMAKE_") + lang + "_OSX_DEPLOYMENT_TARGET_FLAG"; const char* deploymentTargetFlag = this->Makefile->GetDefinition(deploymentTargetFlagVar); - if (!archs.empty() && !lang.empty() && - (lang[0] == 'C' || lang[0] == 'F' || lang[0] == 'O')) { - for (std::string const& arch : archs) { - flags += " -arch "; - flags += arch; - } - } - - if (sysrootFlag && *sysrootFlag && sysroot && *sysroot) { - flags += " "; - flags += sysrootFlag; - flags += " "; - flags += this->ConvertToOutputFormat(sysroot, SHELL); - } - if (deploymentTargetFlag && *deploymentTargetFlag && deploymentTarget && *deploymentTarget) { flags += " "; @@ -1864,7 +1969,8 @@ bool cmLocalGenerator::GetRealDependency(const std::string& inName, case cmStateEnums::SHARED_LIBRARY: case cmStateEnums::MODULE_LIBRARY: case cmStateEnums::UNKNOWN_LIBRARY: - dep = target->GetLocation(config); + dep = target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact, + /*realname=*/true); return true; case cmStateEnums::OBJECT_LIBRARY: // An object library has no single file on which to depend. @@ -1898,8 +2004,16 @@ bool cmLocalGenerator::GetRealDependency(const std::string& inName, // Treat the name as relative to the source directory in which it // was given. - dep = cmStrCat(this->StateSnapshot.GetDirectory().GetCurrentSource(), '/', - inName); + dep = cmStrCat(this->GetCurrentSourceDirectory(), '/', inName); + + // If the in-source path does not exist, assume it instead lives in the + // binary directory. + if (!cmSystemTools::FileExists(dep)) { + dep = cmStrCat(this->GetCurrentBinaryDirectory(), '/', inName); + } + + dep = cmSystemTools::CollapseFullPath(dep, this->GetBinaryDirectory()); + return true; } @@ -2004,17 +2118,22 @@ void cmLocalGenerator::AddCompilerRequirementFlag( langStdMap["OBJC"].emplace_back("99"); langStdMap["OBJC"].emplace_back("90"); + langStdMap["CUDA"].emplace_back("20"); + langStdMap["CUDA"].emplace_back("17"); langStdMap["CUDA"].emplace_back("14"); langStdMap["CUDA"].emplace_back("11"); - langStdMap["CUDA"].emplace_back("98"); + langStdMap["CUDA"].emplace_back("03"); } std::string standard(standardProp); - + if (lang == "CUDA" && standard == "98") { + standard = "03"; + } std::vector<std::string>& stds = langStdMap[lang]; auto stdIt = std::find(stds.begin(), stds.end(), standard); if (stdIt == stds.end()) { + std::string e = lang + "_STANDARD is set to invalid value '" + standard + "'"; this->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( @@ -2296,175 +2415,177 @@ void cmLocalGenerator::AppendFlags( void cmLocalGenerator::AppendFlagEscape(std::string& flags, const std::string& rawFlag) const { - this->AppendFlags(flags, this->EscapeForShell(rawFlag)); + this->AppendFlags( + flags, + this->EscapeForShell(rawFlag, false, false, false, this->IsNinjaMulti())); } void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) { - // FIXME: Handle all configurations in multi-config generators. - std::string config; - if (!this->GetGlobalGenerator()->IsMultiConfig()) { - config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + std::vector<std::string> configsList; + std::string configDefault = this->Makefile->GetConfigurations(configsList); + if (configsList.empty()) { + configsList.push_back(configDefault); } - const std::string buildType = cmSystemTools::UpperCase(config); - // FIXME: Refactor collection of sources to not evaluate object libraries. - std::vector<cmSourceFile*> sources; - target->GetSourceFiles(sources, buildType); - - for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) { - auto langSources = - std::count_if(sources.begin(), sources.end(), [lang](cmSourceFile* sf) { - return lang == sf->GetLanguage() && - !sf->GetProperty("SKIP_PRECOMPILE_HEADERS"); - }); - if (langSources == 0) { - continue; - } + for (std::string const& config : configsList) { + const std::string buildType = cmSystemTools::UpperCase(config); - const std::string pchSource = target->GetPchSource(config, lang); - const std::string pchHeader = target->GetPchHeader(config, lang); + // FIXME: Refactor collection of sources to not evaluate object libraries. + std::vector<cmSourceFile*> sources; + target->GetSourceFiles(sources, buildType); - if (pchSource.empty() || pchHeader.empty()) { - continue; - } - - const std::string pchExtension = - this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION"); + for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) { + auto langSources = std::count_if( + sources.begin(), sources.end(), [lang](cmSourceFile* sf) { + return lang == sf->GetLanguage() && + !sf->GetProperty("SKIP_PRECOMPILE_HEADERS"); + }); + if (langSources == 0) { + continue; + } - if (pchExtension.empty()) { - continue; - } + const std::string pchSource = target->GetPchSource(config, lang); + const std::string pchHeader = target->GetPchHeader(config, lang); - const char* pchReuseFrom = - target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); + if (pchSource.empty() || pchHeader.empty()) { + continue; + } - auto pch_sf = this->Makefile->GetOrCreateSource( - pchSource, false, cmSourceFileLocationKind::Known); + const std::string pchExtension = + this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION"); - if (!this->GetGlobalGenerator()->IsXcode()) { - if (!pchReuseFrom) { - target->AddSource(pchSource, true); + if (pchExtension.empty()) { + continue; } - const std::string pchFile = target->GetPchFile(config, lang); + const char* pchReuseFrom = + target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); - // Exclude the pch files from linking - if (this->Makefile->IsOn("CMAKE_LINK_PCH")) { - if (!pchReuseFrom) { - pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str()); - } else { - auto reuseTarget = - this->GlobalGenerator->FindGeneratorTarget(pchReuseFrom); + auto pch_sf = this->Makefile->GetOrCreateSource( + pchSource, false, cmSourceFileLocationKind::Known); - if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) { + if (!this->GetGlobalGenerator()->IsXcode()) { + if (!pchReuseFrom) { + target->AddSource(pchSource, true); + } - const std::string pdb_prefix = - this->GetGlobalGenerator()->IsMultiConfig() - ? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/") - : ""; + const std::string pchFile = target->GetPchFile(config, lang); - const std::string target_compile_pdb_dir = cmStrCat( - target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/", - target->GetName(), ".dir/"); + // Exclude the pch files from linking + if (this->Makefile->IsOn("CMAKE_LINK_PCH")) { + if (!pchReuseFrom) { + pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str()); + } else { + auto reuseTarget = + this->GlobalGenerator->FindGeneratorTarget(pchReuseFrom); - const std::string copy_script = - cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake"); - cmGeneratedFileStream file(copy_script); + if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) { - file << "# CMake generated file\n"; - for (auto extension : { ".pdb", ".idb" }) { - const std::string from_file = cmStrCat( - reuseTarget->GetLocalGenerator()->GetCurrentBinaryDirectory(), - "/", pchReuseFrom, ".dir/${PDB_PREFIX}", pchReuseFrom, - extension); + const std::string pdb_prefix = + this->GetGlobalGenerator()->IsMultiConfig() + ? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/") + : ""; - const std::string to_dir = cmStrCat( + const std::string target_compile_pdb_dir = cmStrCat( target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/", - target->GetName(), ".dir/${PDB_PREFIX}"); + target->GetName(), ".dir/"); - const std::string to_file = - cmStrCat(to_dir, pchReuseFrom, extension); + const std::string copy_script = + cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake"); + cmGeneratedFileStream file(copy_script); - std::string dest_file = to_file; + file << "# CMake generated file\n"; + for (auto extension : { ".pdb", ".idb" }) { + const std::string from_file = + cmStrCat(reuseTarget->GetLocalGenerator() + ->GetCurrentBinaryDirectory(), + "/", pchReuseFrom, ".dir/${PDB_PREFIX}", + pchReuseFrom, extension); - const std::string prefix = target->GetSafeProperty("PREFIX"); - if (!prefix.empty()) { - dest_file = cmStrCat(to_dir, prefix, pchReuseFrom, extension); - } + const std::string to_dir = cmStrCat( + target->GetLocalGenerator()->GetCurrentBinaryDirectory(), + "/", target->GetName(), ".dir/${PDB_PREFIX}"); + + const std::string to_file = + cmStrCat(to_dir, pchReuseFrom, extension); + + std::string dest_file = to_file; + + const std::string prefix = target->GetSafeProperty("PREFIX"); + if (!prefix.empty()) { + dest_file = + cmStrCat(to_dir, prefix, pchReuseFrom, extension); + } - file << "if (EXISTS \"" << from_file << "\" AND \"" << from_file - << "\" IS_NEWER_THAN \"" << dest_file << "\")\n"; - file << " file(COPY \"" << from_file << "\"" - << " DESTINATION \"" << to_dir << "\")\n"; - if (!prefix.empty()) { - file << " file(REMOVE \"" << dest_file << "\")\n"; - file << " file(RENAME \"" << to_file << "\" \"" << dest_file + file << "if (EXISTS \"" << from_file << "\" AND \"" + << from_file << "\" IS_NEWER_THAN \"" << dest_file << "\")\n"; + file << " file(COPY \"" << from_file << "\"" + << " DESTINATION \"" << to_dir << "\")\n"; + if (!prefix.empty()) { + file << " file(REMOVE \"" << dest_file << "\")\n"; + file << " file(RENAME \"" << to_file << "\" \"" << dest_file + << "\")\n"; + } + file << "endif()\n"; } - file << "endif()\n"; - } - cmCustomCommandLines commandLines; - cmCustomCommandLine currentLine; - currentLine.push_back(cmSystemTools::GetCMakeCommand()); - currentLine.push_back(cmStrCat("-DPDB_PREFIX=", pdb_prefix)); - currentLine.push_back("-P"); - currentLine.push_back(copy_script); - commandLines.push_back(std::move(currentLine)); - - const std::string no_main_dependency; - const std::vector<std::string> no_deps; - const char* no_message = ""; - const char* no_current_dir = nullptr; - std::vector<std::string> no_byproducts; - - std::vector<std::string> outputs; - outputs.push_back(cmStrCat(target_compile_pdb_dir, pdb_prefix, - pchReuseFrom, ".pdb")); - - if (this->GetGlobalGenerator()->IsMultiConfig()) { - this->Makefile->AddCustomCommandToTarget( - target->GetName(), outputs, no_deps, commandLines, - cmCustomCommandType::PRE_BUILD, no_message, no_current_dir); - } else { - cmImplicitDependsList no_implicit_depends; - cmSourceFile* copy_rule = - this->Makefile->AddCustomCommandToOutput( + cmCustomCommandLines commandLines = cmMakeSingleCommandLine( + { cmSystemTools::GetCMakeCommand(), + cmStrCat("-DPDB_PREFIX=", pdb_prefix), "-P", copy_script }); + + const std::string no_main_dependency; + const std::vector<std::string> no_deps; + const char* no_message = ""; + const char* no_current_dir = nullptr; + std::vector<std::string> no_byproducts; + + std::vector<std::string> outputs; + outputs.push_back(cmStrCat(target_compile_pdb_dir, pdb_prefix, + pchReuseFrom, ".pdb")); + + if (this->GetGlobalGenerator()->IsVisualStudio()) { + this->AddCustomCommandToTarget( + target->GetName(), outputs, no_deps, commandLines, + cmCustomCommandType::PRE_BUILD, no_message, no_current_dir); + } else { + cmImplicitDependsList no_implicit_depends; + cmSourceFile* copy_rule = this->AddCustomCommandToOutput( outputs, no_byproducts, no_deps, no_main_dependency, no_implicit_depends, commandLines, no_message, no_current_dir); - if (copy_rule) { - target->AddSource(copy_rule->ResolveFullPath()); + if (copy_rule) { + target->AddSource(copy_rule->ResolveFullPath()); + } } - } - target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY", - target_compile_pdb_dir.c_str()); - } + target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY", + target_compile_pdb_dir); + } - std::string pchSourceObj = - reuseTarget->GetPchFileObject(config, lang); + std::string pchSourceObj = + reuseTarget->GetPchFileObject(config, lang); - // Link to the pch object file - target->Target->AppendProperty( - "LINK_FLAGS", - cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL)) - .c_str(), - true); + // Link to the pch object file + target->Target->AppendProperty( + "LINK_FLAGS", + cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL)), + true); + } + } else { + pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str()); } - } else { - pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str()); - } - // Add pchHeader to source files, which will - // be grouped as "Precompile Header File" - auto pchHeader_sf = this->Makefile->GetOrCreateSource( - pchHeader, false, cmSourceFileLocationKind::Known); - std::string err; - pchHeader_sf->ResolveFullPath(&err); - target->AddSource(pchHeader); + // Add pchHeader to source files, which will + // be grouped as "Precompile Header File" + auto pchHeader_sf = this->Makefile->GetOrCreateSource( + pchHeader, false, cmSourceFileLocationKind::Known); + std::string err; + pchHeader_sf->ResolveFullPath(&err); + target->AddSource(pchHeader); + } } } } @@ -2516,8 +2637,7 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) batchSize = filtered_sources.size(); } - for (size_t itemsLeft = filtered_sources.size(), chunk = batchSize, - batch = 0; + for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0; itemsLeft > 0; itemsLeft -= chunk, ++batch) { chunk = std::min(itemsLeft, batchSize); @@ -2629,11 +2749,11 @@ void cmLocalGenerator::AppendPositionIndependentLinkerFlags( } void cmLocalGenerator::AppendCompileOptions(std::string& options, - const char* options_list, + std::string const& options_list, const char* regex) const { // Short-circuit if there are no options. - if (!options_list) { + if (options_list.empty()) { return; } @@ -2687,11 +2807,11 @@ void cmLocalGenerator::AppendCompileOptions( } void cmLocalGenerator::AppendIncludeDirectories( - std::vector<std::string>& includes, const char* includes_list, + std::vector<std::string>& includes, const std::string& includes_list, const cmSourceFile& sourceFile) const { // Short-circuit if there are no includes. - if (!includes_list) { + if (includes_list.empty()) { return; } @@ -2794,11 +2914,11 @@ void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines, // command line without any escapes. However we still have to // get the '$' and '#' characters through WMake as '$$' and // '$#'. - for (const char* c = define.c_str(); *c; ++c) { - if (*c == '$' || *c == '#') { + for (char c : define) { + if (c == '$' || c == '#') { def += '$'; } - def += *c; + def += c; } } else { // Make the definition appear properly on the command line. Use @@ -2885,7 +3005,7 @@ class cmInstallTargetGeneratorLocal : public cmInstallTargetGenerator { public: cmInstallTargetGeneratorLocal(cmLocalGenerator* lg, std::string const& t, - const char* dest, bool implib) + std::string const& dest, bool implib) : cmInstallTargetGenerator( t, dest, implib, "", std::vector<std::string>(), "Unspecified", cmInstallGenerator::SelectMessageLevel(lg->GetMakefile()), false, @@ -2901,15 +3021,15 @@ void cmLocalGenerator::GenerateTargetInstallRules( { // Convert the old-style install specification from each target to // an install generator and run it. - const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets(); - for (cmGeneratorTarget* l : tgts) { + const auto& tgts = this->GetGeneratorTargets(); + for (const auto& l : tgts) { if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } // Include the user-specified pre-install script for this target. if (const char* preinstall = l->GetProperty("PRE_INSTALL_SCRIPT")) { - cmInstallScriptGenerator g(preinstall, false, nullptr, false); + cmInstallScriptGenerator g(preinstall, false, "", false); g.Generate(os, config, configurationTypes); } @@ -2930,8 +3050,8 @@ void cmLocalGenerator::GenerateTargetInstallRules( case cmStateEnums::STATIC_LIBRARY: case cmStateEnums::MODULE_LIBRARY: { // Use a target install generator. - cmInstallTargetGeneratorLocal g(this, l->GetName(), - destination.c_str(), false); + cmInstallTargetGeneratorLocal g(this, l->GetName(), destination, + false); g.Generate(os, config, configurationTypes); } break; case cmStateEnums::SHARED_LIBRARY: { @@ -2939,19 +3059,19 @@ void cmLocalGenerator::GenerateTargetInstallRules( // Special code to handle DLL. Install the import library // to the normal destination and the DLL to the runtime // destination. - cmInstallTargetGeneratorLocal g1(this, l->GetName(), - destination.c_str(), true); + cmInstallTargetGeneratorLocal g1(this, l->GetName(), destination, + true); g1.Generate(os, config, configurationTypes); // We also skip over the leading slash given by the user. destination = l->Target->GetRuntimeInstallPath().substr(1); cmSystemTools::ConvertToUnixSlashes(destination); - cmInstallTargetGeneratorLocal g2(this, l->GetName(), - destination.c_str(), false); + cmInstallTargetGeneratorLocal g2(this, l->GetName(), destination, + false); g2.Generate(os, config, configurationTypes); #else // Use a target install generator. - cmInstallTargetGeneratorLocal g(this, l->GetName(), - destination.c_str(), false); + cmInstallTargetGeneratorLocal g(this, l->GetName(), destination, + false); g.Generate(os, config, configurationTypes); #endif } break; @@ -2962,7 +3082,7 @@ void cmLocalGenerator::GenerateTargetInstallRules( // Include the user-specified post-install script for this target. if (const char* postinstall = l->GetProperty("POST_INSTALL_SCRIPT")) { - cmInstallScriptGenerator g(postinstall, false, nullptr, false); + cmInstallScriptGenerator g(postinstall, false, "", false); g.Generate(os, config, configurationTypes); } } @@ -3118,6 +3238,11 @@ bool cmLocalGenerator::IsNMake() const return this->GetState()->UseNMake(); } +bool cmLocalGenerator::IsNinjaMulti() const +{ + return this->GetState()->UseNinjaMulti(); +} + std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( const cmSourceFile& source, std::string const& dir_max, bool* hasSourceExtension, char const* customOutputExtension) @@ -3446,3 +3571,245 @@ void cmLocalGenerator::GenerateFrameworkInfoPList( cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION"); mf->ConfigureFile(inFile, fname, false, false, false); } + +namespace { +void CreateGeneratedSource(cmLocalGenerator& lg, const std::string& output, + cmCommandOrigin origin, + const cmListFileBacktrace& lfbt) +{ + if (cmGeneratorExpression::Find(output) == std::string::npos) { + // Outputs without generator expressions from the project are already + // created and marked as generated. Do not mark them again, because + // other commands might have overwritten the property. + if (origin == cmCommandOrigin::Generator) { + lg.GetMakefile()->GetOrCreateGeneratedSource(output); + } + } else { + lg.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + "Generator expressions in custom command outputs are not implemented!", + lfbt); + } +} + +void CreateGeneratedSources(cmLocalGenerator& lg, + const std::vector<std::string>& outputs, + cmCommandOrigin origin, + const cmListFileBacktrace& lfbt) +{ + for (std::string const& o : outputs) { + CreateGeneratedSource(lg, o, origin, lfbt); + } +} + +cmSourceFile* AddCustomCommand( + cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, + const std::vector<std::string>& outputs, + const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, const std::string& main_dependency, + const cmImplicitDependsList& implicit_depends, + const cmCustomCommandLines& commandLines, const char* comment, + const char* workingDir, bool replace, bool escapeOldStyle, + bool uses_terminal, bool command_expand_lists, const std::string& depfile, + const std::string& job_pool) +{ + cmMakefile* mf = lg.GetMakefile(); + + // Choose a source file on which to store the custom command. + cmSourceFile* file = nullptr; + if (!commandLines.empty() && !main_dependency.empty()) { + // The main dependency was specified. Use it unless a different + // custom command already used it. + file = mf->GetSource(main_dependency); + if (file && file->GetCustomCommand() && !replace) { + // The main dependency already has a custom command. + if (commandLines == file->GetCustomCommand()->GetCommandLines()) { + // The existing custom command is identical. Silently ignore + // the duplicate. + return file; + } + // The existing custom command is different. We need to + // generate a rule file for this new command. + file = nullptr; + } else if (!file) { + file = mf->CreateSource(main_dependency); + } + } + + // Generate a rule file if the main dependency is not available. + if (!file) { + cmGlobalGenerator* gg = lg.GetGlobalGenerator(); + + // Construct a rule file associated with the first output produced. + std::string outName = gg->GenerateRuleFile(outputs[0]); + + // Check if the rule file already exists. + file = mf->GetSource(outName, cmSourceFileLocationKind::Known); + if (file && file->GetCustomCommand() && !replace) { + // The rule file already exists. + if (commandLines != file->GetCustomCommand()->GetCommandLines()) { + lg.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Attempt to add a custom rule to output\n ", outName, + "\nwhich already has a custom rule."), + lfbt); + } + return file; + } + + // Create a cmSourceFile for the rule file. + if (!file) { + file = mf->CreateSource(outName, true, cmSourceFileLocationKind::Known); + } + file->SetProperty("__CMAKE_RULE", "1"); + } + + // Attach the custom command to the file. + if (file) { + // Construct a complete list of dependencies. + std::vector<std::string> depends2(depends); + if (!main_dependency.empty()) { + depends2.push_back(main_dependency); + } + + std::unique_ptr<cmCustomCommand> cc = cm::make_unique<cmCustomCommand>( + outputs, byproducts, depends2, commandLines, lfbt, comment, workingDir); + cc->SetEscapeOldStyle(escapeOldStyle); + cc->SetEscapeAllowMakeVars(true); + cc->SetImplicitDepends(implicit_depends); + cc->SetUsesTerminal(uses_terminal); + cc->SetCommandExpandLists(command_expand_lists); + cc->SetDepfile(depfile); + cc->SetJobPool(job_pool); + file->SetCustomCommand(std::move(cc)); + + mf->AddSourceOutputs(file, outputs, byproducts); + } + return file; +} +} + +namespace detail { +void AddCustomCommandToTarget(cmLocalGenerator& lg, + const cmListFileBacktrace& lfbt, + cmCommandOrigin origin, cmTarget* target, + const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, + const cmCustomCommandLines& commandLines, + cmCustomCommandType type, const char* comment, + const char* workingDir, bool escapeOldStyle, + bool uses_terminal, const std::string& depfile, + const std::string& job_pool, + bool command_expand_lists) +{ + cmMakefile* mf = lg.GetMakefile(); + + // Always create the byproduct sources and mark them generated. + CreateGeneratedSources(lg, byproducts, origin, lfbt); + + // Add the command to the appropriate build step for the target. + std::vector<std::string> no_output; + cmCustomCommand cc(no_output, byproducts, depends, commandLines, lfbt, + comment, workingDir); + cc.SetEscapeOldStyle(escapeOldStyle); + cc.SetEscapeAllowMakeVars(true); + cc.SetUsesTerminal(uses_terminal); + cc.SetCommandExpandLists(command_expand_lists); + cc.SetDepfile(depfile); + cc.SetJobPool(job_pool); + switch (type) { + case cmCustomCommandType::PRE_BUILD: + target->AddPreBuildCommand(std::move(cc)); + break; + case cmCustomCommandType::PRE_LINK: + target->AddPreLinkCommand(std::move(cc)); + break; + case cmCustomCommandType::POST_BUILD: + target->AddPostBuildCommand(std::move(cc)); + break; + } + + mf->AddTargetByproducts(target, byproducts); +} + +cmSourceFile* AddCustomCommandToOutput( + cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, + cmCommandOrigin origin, const std::vector<std::string>& outputs, + const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, const std::string& main_dependency, + const cmImplicitDependsList& implicit_depends, + const cmCustomCommandLines& commandLines, const char* comment, + const char* workingDir, bool replace, bool escapeOldStyle, + bool uses_terminal, bool command_expand_lists, const std::string& depfile, + const std::string& job_pool) +{ + // Always create the output sources and mark them generated. + CreateGeneratedSources(lg, outputs, origin, lfbt); + CreateGeneratedSources(lg, byproducts, origin, lfbt); + + return AddCustomCommand( + lg, lfbt, outputs, byproducts, depends, main_dependency, implicit_depends, + commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal, + command_expand_lists, depfile, job_pool); +} + +void AppendCustomCommandToOutput(cmLocalGenerator& lg, + const cmListFileBacktrace& lfbt, + const std::string& output, + const std::vector<std::string>& depends, + const cmImplicitDependsList& implicit_depends, + const cmCustomCommandLines& commandLines) +{ + // Lookup an existing command. + if (cmSourceFile* sf = lg.GetMakefile()->GetSourceFileWithOutput(output)) { + if (cmCustomCommand* cc = sf->GetCustomCommand()) { + cc->AppendCommands(commandLines); + cc->AppendDepends(depends); + cc->AppendImplicitDepends(implicit_depends); + return; + } + } + + // No existing command found. + lg.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Attempt to append to output\n ", output, + "\nwhich is not already a custom command output."), + lfbt); +} + +void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, + cmCommandOrigin origin, cmTarget* target, + const cmUtilityOutput& force, const char* workingDir, + const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, + const cmCustomCommandLines& commandLines, + bool escapeOldStyle, const char* comment, + bool uses_terminal, bool command_expand_lists, + const std::string& job_pool) +{ + // Always create the byproduct sources and mark them generated. + CreateGeneratedSource(lg, force.Name, origin, lfbt); + CreateGeneratedSources(lg, byproducts, origin, lfbt); + + // Use an empty comment to avoid generation of default comment. + if (!comment) { + comment = ""; + } + + std::string no_main_dependency; + cmImplicitDependsList no_implicit_depends; + cmSourceFile* rule = AddCustomCommand( + lg, lfbt, { force.Name }, byproducts, depends, no_main_dependency, + no_implicit_depends, commandLines, comment, workingDir, /*replace=*/false, + escapeOldStyle, uses_terminal, command_expand_lists, /*depfile=*/"", + job_pool); + if (rule) { + lg.GetMakefile()->AddTargetByproducts(target, byproducts); + } + + if (!force.NameCMP0049.empty()) { + target->AddSource(force.NameCMP0049); + } +} +} diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 12359db..88194b7 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -7,6 +7,7 @@ #include <iosfwd> #include <map> +#include <memory> #include <set> #include <string> #include <unordered_map> @@ -14,6 +15,7 @@ #include "cm_kwiml.h" +#include "cmCustomCommandTypes.h" #include "cmListFileCache.h" #include "cmMessageType.h" #include "cmOutputConverter.h" @@ -22,13 +24,16 @@ class cmComputeLinkInformation; class cmCustomCommandGenerator; +class cmCustomCommandLines; class cmGeneratorTarget; class cmGlobalGenerator; +class cmImplicitDependsList; class cmLinkLineComputer; class cmMakefile; class cmRulePlaceholderExpander; class cmSourceFile; class cmState; +class cmTarget; class cmake; /** \class cmLocalGenerator @@ -143,14 +148,16 @@ public: bool forResponseFile = false, const std::string& config = ""); - const std::vector<cmGeneratorTarget*>& GetGeneratorTargets() const + using GeneratorTargetVector = + std::vector<std::unique_ptr<cmGeneratorTarget>>; + const GeneratorTargetVector& GetGeneratorTargets() const { return this->GeneratorTargets; } - void AddGeneratorTarget(cmGeneratorTarget* gt); + void AddGeneratorTarget(std::unique_ptr<cmGeneratorTarget> gt); void AddImportedGeneratorTarget(cmGeneratorTarget* gt); - void AddOwnedImportedGeneratorTarget(cmGeneratorTarget* gt); + void AddOwnedImportedGeneratorTarget(std::unique_ptr<cmGeneratorTarget> gt); cmGeneratorTarget* FindLocalNonAliasGeneratorTarget( const std::string& name) const; @@ -160,15 +167,8 @@ public: * Process a list of include directories */ void AppendIncludeDirectories(std::vector<std::string>& includes, - const char* includes_list, - const cmSourceFile& sourceFile) const; - void AppendIncludeDirectories(std::vector<std::string>& includes, std::string const& includes_list, - const cmSourceFile& sourceFile) const - { - this->AppendIncludeDirectories(includes, includes_list.c_str(), - sourceFile); - } + const cmSourceFile& sourceFile) const; void AppendIncludeDirectories(std::vector<std::string>& includes, const std::vector<std::string>& includes_vec, const cmSourceFile& sourceFile) const; @@ -188,14 +188,9 @@ public: * Encode a list of compile options for the compiler * command line. */ - void AppendCompileOptions(std::string& options, const char* options_list, - const char* regex = nullptr) const; void AppendCompileOptions(std::string& options, std::string const& options_list, - const char* regex = nullptr) const - { - this->AppendCompileOptions(options, options_list.c_str(), regex); - } + const char* regex = nullptr) const; void AppendCompileOptions(std::string& options, const std::vector<std::string>& options_vec, const char* regex = nullptr) const; @@ -292,6 +287,51 @@ public: cmGeneratorTarget* target, const std::string& lang, const std::string& config); + /** + * Add a custom PRE_BUILD, PRE_LINK, or POST_BUILD command to a target. + */ + cmTarget* AddCustomCommandToTarget( + const std::string& target, const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, + const cmCustomCommandLines& commandLines, cmCustomCommandType type, + const char* comment, const char* workingDir, bool escapeOldStyle = true, + bool uses_terminal = false, const std::string& depfile = "", + const std::string& job_pool = "", bool command_expand_lists = false, + cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject); + + /** + * Add a custom command to a source file. + */ + cmSourceFile* AddCustomCommandToOutput( + const std::string& output, const std::vector<std::string>& depends, + const std::string& main_dependency, + const cmCustomCommandLines& commandLines, const char* comment, + const char* workingDir, bool replace = false, bool escapeOldStyle = true, + bool uses_terminal = false, bool command_expand_lists = false, + const std::string& depfile = "", const std::string& job_pool = ""); + cmSourceFile* AddCustomCommandToOutput( + const std::vector<std::string>& outputs, + const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, + const std::string& main_dependency, + const cmImplicitDependsList& implicit_depends, + const cmCustomCommandLines& commandLines, const char* comment, + const char* workingDir, bool replace = false, bool escapeOldStyle = true, + bool uses_terminal = false, bool command_expand_lists = false, + const std::string& depfile = "", const std::string& job_pool = ""); + + /** + * Add a utility to the build. A utility target is a command that is run + * every time the target is built. + */ + cmTarget* AddUtilityCommand( + const std::string& utilityName, bool excludeFromAll, + const char* workingDir, const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, + const cmCustomCommandLines& commandLines, bool escapeOldStyle = true, + const char* comment = nullptr, bool uses_terminal = false, + bool command_expand_lists = false, const std::string& job_pool = ""); + std::string GetProjectName() const; /** Compute the language used to compile the given source file. */ @@ -414,6 +454,7 @@ public: bool IsWatcomWMake() const; bool IsMinGWMake() const; bool IsNMake() const; + bool IsNinjaMulti() const; void IssueMessage(MessageType t, std::string const& text) const; @@ -461,11 +502,11 @@ protected: using GeneratorTargetMap = std::unordered_map<std::string, cmGeneratorTarget*>; GeneratorTargetMap GeneratorTargetSearchIndex; - std::vector<cmGeneratorTarget*> GeneratorTargets; + GeneratorTargetVector GeneratorTargets; std::set<cmGeneratorTarget const*> WarnCMP0063; GeneratorTargetMap ImportedGeneratorTargets; - std::vector<cmGeneratorTarget*> OwnedImportedGeneratorTargets; + GeneratorTargetVector OwnedImportedGeneratorTargets; std::map<std::string, std::string> AliasTargets; std::map<std::string, std::string> Compilers; @@ -494,4 +535,46 @@ bool cmLocalGeneratorCheckObjectName(std::string& objName, std::string::size_type max_total_len); #endif +namespace detail { +void AddCustomCommandToTarget(cmLocalGenerator& lg, + const cmListFileBacktrace& lfbt, + cmCommandOrigin origin, cmTarget* target, + const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, + const cmCustomCommandLines& commandLines, + cmCustomCommandType type, const char* comment, + const char* workingDir, bool escapeOldStyle, + bool uses_terminal, const std::string& depfile, + const std::string& job_pool, + bool command_expand_lists); + +cmSourceFile* AddCustomCommandToOutput( + cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, + cmCommandOrigin origin, const std::vector<std::string>& outputs, + const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, const std::string& main_dependency, + const cmImplicitDependsList& implicit_depends, + const cmCustomCommandLines& commandLines, const char* comment, + const char* workingDir, bool replace, bool escapeOldStyle, + bool uses_terminal, bool command_expand_lists, const std::string& depfile, + const std::string& job_pool); + +void AppendCustomCommandToOutput(cmLocalGenerator& lg, + const cmListFileBacktrace& lfbt, + const std::string& output, + const std::vector<std::string>& depends, + const cmImplicitDependsList& implicit_depends, + const cmCustomCommandLines& commandLines); + +void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, + cmCommandOrigin origin, cmTarget* target, + const cmUtilityOutput& force, const char* workingDir, + const std::vector<std::string>& byproducts, + const std::vector<std::string>& depends, + const cmCustomCommandLines& commandLines, + bool escapeOldStyle, const char* comment, + bool uses_terminal, bool command_expand_lists, + const std::string& job_pool); +} + #endif diff --git a/Source/cmLocalGhsMultiGenerator.cxx b/Source/cmLocalGhsMultiGenerator.cxx index 4b10798..098fa5a 100644 --- a/Source/cmLocalGhsMultiGenerator.cxx +++ b/Source/cmLocalGhsMultiGenerator.cxx @@ -5,6 +5,8 @@ #include <algorithm> #include <utility> +#include <cmext/algorithm> + #include "cmGeneratorTarget.h" #include "cmGhsMultiTargetGenerator.h" #include "cmGlobalGenerator.h" @@ -50,10 +52,11 @@ void cmLocalGhsMultiGenerator::GenerateTargetsDepthFirst( void cmLocalGhsMultiGenerator::Generate() { - std::vector<cmGeneratorTarget*> remaining = this->GetGeneratorTargets(); + std::vector<cmGeneratorTarget*> remaining; + cm::append(remaining, this->GetGeneratorTargets()); for (auto& t : remaining) { if (t) { - GenerateTargetsDepthFirst(t, remaining); + this->GenerateTargetsDepthFirst(t, remaining); } } } diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 134bbe1..be1dd0d 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -29,6 +29,7 @@ #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmTarget.h" #include "cmake.h" cmLocalNinjaGenerator::cmLocalNinjaGenerator(cmGlobalGenerator* gg, @@ -61,7 +62,12 @@ void cmLocalNinjaGenerator::Generate() this->HomeRelativeOutputPath.clear(); } - this->WriteProcessedMakefile(this->GetBuildFileStream()); + if (this->GetGlobalGenerator()->IsMultiConfig()) { + for (auto const& config : this->GetConfigNames()) { + this->WriteProcessedMakefile(this->GetImplFileStream(config)); + } + } + this->WriteProcessedMakefile(this->GetCommonFileStream()); #ifdef NINJA_GEN_VERBOSE_FILES this->WriteProcessedMakefile(this->GetRulesFileStream()); #endif @@ -82,18 +88,26 @@ void cmLocalNinjaGenerator::Generate() } } - for (cmGeneratorTarget* target : this->GetGeneratorTargets()) { + for (const auto& target : this->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - auto tg = cmNinjaTargetGenerator::New(target); + auto tg = cmNinjaTargetGenerator::New(target.get()); if (tg) { - tg->Generate(); + if (target->Target->IsPerConfig()) { + for (auto const& config : this->GetConfigNames()) { + tg->Generate(config); + } + } else { + tg->Generate(""); + } } } - this->WriteCustomCommandBuildStatements(); - this->AdditionalCleanFiles(); + for (auto const& config : this->GetConfigNames()) { + this->WriteCustomCommandBuildStatements(config); + this->AdditionalCleanFiles(config); + } } // TODO: Picked up from cmLocalUnixMakefileGenerator3. Refactor it. @@ -140,9 +154,15 @@ std::string cmLocalNinjaGenerator::ConvertToIncludeReference( // Private methods. -cmGeneratedFileStream& cmLocalNinjaGenerator::GetBuildFileStream() const +cmGeneratedFileStream& cmLocalNinjaGenerator::GetImplFileStream( + const std::string& config) const { - return *this->GetGlobalNinjaGenerator()->GetBuildFileStream(); + return *this->GetGlobalNinjaGenerator()->GetImplFileStream(config); +} + +cmGeneratedFileStream& cmLocalNinjaGenerator::GetCommonFileStream() const +{ + return *this->GetGlobalNinjaGenerator()->GetCommonFileStream(); } cmGeneratedFileStream& cmLocalNinjaGenerator::GetRulesFileStream() const @@ -162,10 +182,22 @@ cmake* cmLocalNinjaGenerator::GetCMakeInstance() void cmLocalNinjaGenerator::WriteBuildFileTop() { - // For the build file. - this->WriteProjectHeader(this->GetBuildFileStream()); - this->WriteNinjaRequiredVersion(this->GetBuildFileStream()); - this->WriteNinjaFilesInclusion(this->GetBuildFileStream()); + this->WriteProjectHeader(this->GetCommonFileStream()); + + if (this->GetGlobalGenerator()->IsMultiConfig()) { + for (auto const& config : this->GetConfigNames()) { + auto& stream = this->GetImplFileStream(config); + this->WriteProjectHeader(stream); + this->WriteNinjaRequiredVersion(stream); + this->WriteNinjaConfigurationVariable(stream, config); + this->WriteNinjaFilesInclusionConfig(stream); + } + } else { + this->WriteNinjaRequiredVersion(this->GetCommonFileStream()); + this->WriteNinjaConfigurationVariable(this->GetCommonFileStream(), + this->GetConfigNames().front()); + } + this->WriteNinjaFilesInclusionCommon(this->GetCommonFileStream()); // For the rule file. this->WriteProjectHeader(this->GetRulesFileStream()); @@ -175,7 +207,8 @@ void cmLocalNinjaGenerator::WriteProjectHeader(std::ostream& os) { cmGlobalNinjaGenerator::WriteDivider(os); os << "# Project: " << this->GetProjectName() << std::endl - << "# Configuration: " << this->ConfigName << std::endl; + << "# Configurations: " << cmJoin(this->GetConfigNames(), ", ") + << std::endl; cmGlobalNinjaGenerator::WriteDivider(os); } @@ -206,6 +239,14 @@ void cmLocalNinjaGenerator::WriteNinjaRequiredVersion(std::ostream& os) << std::endl; } +void cmLocalNinjaGenerator::WriteNinjaConfigurationVariable( + std::ostream& os, const std::string& config) +{ + cmGlobalNinjaGenerator::WriteVariable( + os, "CONFIGURATION", config, + "Set configuration variable for custom commands."); +} + void cmLocalNinjaGenerator::WritePools(std::ostream& os) { cmGlobalNinjaGenerator::WriteDivider(os); @@ -235,7 +276,21 @@ void cmLocalNinjaGenerator::WritePools(std::ostream& os) } } -void cmLocalNinjaGenerator::WriteNinjaFilesInclusion(std::ostream& os) +void cmLocalNinjaGenerator::WriteNinjaFilesInclusionConfig(std::ostream& os) +{ + cmGlobalNinjaGenerator::WriteDivider(os); + os << "# Include auxiliary files.\n" + << "\n"; + cmGlobalNinjaGenerator* ng = this->GetGlobalNinjaGenerator(); + std::string const ninjaCommonFile = + ng->NinjaOutputPath(cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE); + std::string const commonFilePath = ng->EncodePath(ninjaCommonFile); + cmGlobalNinjaGenerator::WriteInclude(os, commonFilePath, + "Include common file."); + os << "\n"; +} + +void cmLocalNinjaGenerator::WriteNinjaFilesInclusionCommon(std::ostream& os) { cmGlobalNinjaGenerator::WriteDivider(os); os << "# Include auxiliary files.\n" @@ -263,25 +318,30 @@ void cmLocalNinjaGenerator::WriteProcessedMakefile(std::ostream& os) } void cmLocalNinjaGenerator::AppendTargetOutputs(cmGeneratorTarget* target, - cmNinjaDeps& outputs) + cmNinjaDeps& outputs, + const std::string& config) { - this->GetGlobalNinjaGenerator()->AppendTargetOutputs(target, outputs); + this->GetGlobalNinjaGenerator()->AppendTargetOutputs(target, outputs, + config); } void cmLocalNinjaGenerator::AppendTargetDepends(cmGeneratorTarget* target, cmNinjaDeps& outputs, + const std::string& config, + const std::string& fileConfig, cmNinjaTargetDepends depends) { - this->GetGlobalNinjaGenerator()->AppendTargetDepends(target, outputs, - depends); + this->GetGlobalNinjaGenerator()->AppendTargetDepends(target, outputs, config, + fileConfig, depends); } void cmLocalNinjaGenerator::AppendCustomCommandDeps( - cmCustomCommandGenerator const& ccg, cmNinjaDeps& ninjaDeps) + cmCustomCommandGenerator const& ccg, cmNinjaDeps& ninjaDeps, + const std::string& config) { for (std::string const& i : ccg.GetDepends()) { std::string dep; - if (this->GetRealDependency(i, this->GetConfigName(), dep)) { + if (this->GetRealDependency(i, config, dep)) { ninjaDeps.push_back( this->GetGlobalNinjaGenerator()->ConvertToNinjaPath(dep)); } @@ -416,6 +476,8 @@ std::string cmLocalNinjaGenerator::BuildCommandLine( void cmLocalNinjaGenerator::AppendCustomCommandLines( cmCustomCommandGenerator const& ccg, std::vector<std::string>& cmdLines) { + auto* gg = this->GetGlobalNinjaGenerator(); + if (ccg.GetNumberOfCommands() > 0) { std::string wd = ccg.GetWorkingDirectory(); if (wd.empty()) { @@ -437,8 +499,10 @@ void cmLocalNinjaGenerator::AppendCustomCommandLines( for (unsigned i = 0; i != ccg.GetNumberOfCommands(); ++i) { cmdLines.push_back(launcher + - this->ConvertToOutputFormat(ccg.GetCommand(i), - cmOutputConverter::SHELL)); + this->ConvertToOutputFormat( + ccg.GetCommand(i), + gg->IsMultiConfig() ? cmOutputConverter::NINJAMULTI + : cmOutputConverter::SHELL)); std::string& cmd = cmdLines.back(); ccg.AppendArguments(i, cmd); @@ -446,14 +510,15 @@ void cmLocalNinjaGenerator::AppendCustomCommandLines( } void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( - cmCustomCommand const* cc, const cmNinjaDeps& orderOnlyDeps) + cmCustomCommand const* cc, const cmNinjaDeps& orderOnlyDeps, + const std::string& config) { cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator(); - if (gg->SeenCustomCommand(cc)) { + if (gg->SeenCustomCommand(cc, config)) { return; } - cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), this); + cmCustomCommandGenerator ccg(*cc, config, this); const std::vector<std::string>& outputs = ccg.GetOutputs(); const std::vector<std::string>& byproducts = ccg.GetByproducts(); @@ -484,7 +549,7 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( } cmNinjaDeps ninjaDeps; - this->AppendCustomCommandDeps(ccg, ninjaDeps); + this->AppendCustomCommandDeps(ccg, ninjaDeps, config); std::vector<std::string> cmdLines; this->AppendCustomCommandLines(ccg, cmdLines); @@ -495,7 +560,7 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( build.Outputs = std::move(ninjaOutputs); build.ExplicitDeps = std::move(ninjaDeps); build.OrderOnlyDeps = orderOnlyDeps; - gg->WriteBuild(this->GetBuildFileStream(), build); + gg->WriteBuild(this->GetImplFileStream(config), build); } else { std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]); // Hash full path to make unique. @@ -507,8 +572,8 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( this->BuildCommandLine(cmdLines, customStep), this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0], cc->GetDepfile(), cc->GetJobPool(), cc->GetUsesTerminal(), - /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, ninjaDeps, - orderOnlyDeps); + /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, config, + ninjaDeps, orderOnlyDeps); } } @@ -524,7 +589,8 @@ void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand const* cc, ins.first->second.insert(target); } -void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements() +void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements( + const std::string& config) { for (cmCustomCommand const* customCommand : this->CustomCommands) { auto i = this->CustomCommandTargets.find(customCommand); @@ -542,15 +608,16 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements() auto j = i->second.begin(); assert(j != i->second.end()); std::vector<std::string> ccTargetDeps; - this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(*j, - ccTargetDeps); + this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure( + *j, ccTargetDeps, config); std::sort(ccTargetDeps.begin(), ccTargetDeps.end()); ++j; for (; j != i->second.end(); ++j) { std::vector<std::string> jDeps; std::vector<std::string> depsIntersection; - this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(*j, jDeps); + this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(*j, jDeps, + config); std::sort(jDeps.begin(), jDeps.end()); std::set_intersection(ccTargetDeps.begin(), ccTargetDeps.end(), jDeps.begin(), jDeps.end(), @@ -558,7 +625,7 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements() ccTargetDeps = depsIntersection; } - this->WriteCustomCommandBuildStatement(i->first, ccTargetDeps); + this->WriteCustomCommandBuildStatement(i->first, ccTargetDeps, config); } } @@ -599,15 +666,13 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( return launcher; } -void cmLocalNinjaGenerator::AdditionalCleanFiles() +void cmLocalNinjaGenerator::AdditionalCleanFiles(const std::string& config) { if (const char* prop_value = this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) { std::vector<std::string> cleanFiles; { - cmExpandList(cmGeneratorExpression::Evaluate( - prop_value, this, - this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")), + cmExpandList(cmGeneratorExpression::Evaluate(prop_value, this, config), cleanFiles); } std::string const& binaryDir = this->GetCurrentBinaryDirectory(); @@ -615,7 +680,7 @@ void cmLocalNinjaGenerator::AdditionalCleanFiles() for (std::string const& cleanFile : cleanFiles) { // Support relative paths gg->AddAdditionalCleanFile( - cmSystemTools::CollapseFullPath(cleanFile, binaryDir)); + cmSystemTools::CollapseFullPath(cleanFile, binaryDir), config); } } } diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h index f64534c..ef160e7 100644 --- a/Source/cmLocalNinjaGenerator.h +++ b/Source/cmLocalNinjaGenerator.h @@ -64,9 +64,11 @@ public: std::string const& customStep = std::string(), cmGeneratorTarget const* target = nullptr) const; - void AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs); + void AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs, + const std::string& config); void AppendTargetDepends( - cmGeneratorTarget* target, cmNinjaDeps& outputs, + cmGeneratorTarget* target, cmNinjaDeps& outputs, const std::string& config, + const std::string& fileConfig, cmNinjaTargetDepends depends = DependOnTargetArtifact); void AddCustomCommandTarget(cmCustomCommand const* cc, @@ -74,7 +76,8 @@ public: void AppendCustomCommandLines(cmCustomCommandGenerator const& ccg, std::vector<std::string>& cmdLines); void AppendCustomCommandDeps(cmCustomCommandGenerator const& ccg, - cmNinjaDeps& ninjaDeps); + cmNinjaDeps& ninjaDeps, + const std::string& config); protected: std::string ConvertToIncludeReference( @@ -83,20 +86,25 @@ protected: bool forceFullPaths = false) override; private: - cmGeneratedFileStream& GetBuildFileStream() const; + cmGeneratedFileStream& GetImplFileStream(const std::string& config) const; + cmGeneratedFileStream& GetCommonFileStream() const; cmGeneratedFileStream& GetRulesFileStream() const; void WriteBuildFileTop(); void WriteProjectHeader(std::ostream& os); void WriteNinjaRequiredVersion(std::ostream& os); - void WriteNinjaFilesInclusion(std::ostream& os); + void WriteNinjaConfigurationVariable(std::ostream& os, + const std::string& config); + void WriteNinjaFilesInclusionConfig(std::ostream& os); + void WriteNinjaFilesInclusionCommon(std::ostream& os); void WriteProcessedMakefile(std::ostream& os); void WritePools(std::ostream& os); void WriteCustomCommandBuildStatement(cmCustomCommand const* cc, - const cmNinjaDeps& orderOnlyDeps); + const cmNinjaDeps& orderOnlyDeps, + const std::string& config); - void WriteCustomCommandBuildStatements(); + void WriteCustomCommandBuildStatements(const std::string& config); std::string MakeCustomLauncher(cmCustomCommandGenerator const& ccg); @@ -104,7 +112,7 @@ private: std::string const& customStep, cmGeneratorTarget const* target) const; - void AdditionalCleanFiles(); + void AdditionalCleanFiles(const std::string& config); std::string HomeRelativeOutputPath; diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 4a70248..63c6680 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -3,16 +3,18 @@ #include "cmLocalUnixMakefileGenerator3.h" #include <algorithm> +#include <cassert> #include <cstdio> #include <sstream> #include <utility> #include <cm/memory> +#include <cm/vector> +#include <cmext/algorithm> #include "cmsys/FStream.hxx" #include "cmsys/Terminal.h" -#include "cmAlgorithms.h" #include "cmCustomCommand.h" // IWYU pragma: keep #include "cmCustomCommandGenerator.h" #include "cmFileTimeCache.h" @@ -106,6 +108,13 @@ cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3( cmLocalUnixMakefileGenerator3::~cmLocalUnixMakefileGenerator3() = default; +std::string cmLocalUnixMakefileGenerator3::GetConfigName() const +{ + auto const& configNames = this->GetConfigNames(); + assert(configNames.size() == 1); + return configNames.front(); +} + void cmLocalUnixMakefileGenerator3::Generate() { // Record whether some options are enabled to avoid checking many @@ -121,12 +130,12 @@ void cmLocalUnixMakefileGenerator3::Generate() // Generate the rule files for each target. cmGlobalUnixMakefileGenerator3* gg = static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator); - for (cmGeneratorTarget* target : this->GetGeneratorTargets()) { + for (const auto& target : this->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } std::unique_ptr<cmMakefileTargetGenerator> tg( - cmMakefileTargetGenerator::New(target)); + cmMakefileTargetGenerator::New(target.get())); if (tg) { tg->WriteRuleFiles(); gg->RecordTargetProgress(tg.get()); @@ -157,15 +166,15 @@ void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath() void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles( std::map<std::string, LocalObjectInfo>& localObjectFiles) { - for (cmGeneratorTarget* gt : this->GetGeneratorTargets()) { + for (const auto& gt : this->GetGeneratorTargets()) { if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } std::vector<cmSourceFile const*> objectSources; - gt->GetObjectSources(objectSources, this->ConfigName); + gt->GetObjectSources(objectSources, this->GetConfigName()); // Compute full path to object file directory for this target. std::string dir = cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), - '/', this->GetTargetDirectory(gt), '/'); + '/', this->GetTargetDirectory(gt.get()), '/'); // Compute the name of each object file. for (cmSourceFile const* sf : objectSources) { bool hasSourceExtension = true; @@ -176,7 +185,7 @@ void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles( } LocalObjectInfo& info = localObjectFiles[objectName]; info.HasSourceExtension = hasSourceExtension; - info.emplace_back(gt, sf->GetLanguage()); + info.emplace_back(gt.get(), sf->GetLanguage()); } } } @@ -352,7 +361,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets( // for each target we just provide a rule to cd up to the top and do a make // on the target std::string localName; - for (cmGeneratorTarget* target : this->GetGeneratorTargets()) { + for (const auto& target : this->GetGeneratorTargets()) { if ((target->GetType() == cmStateEnums::EXECUTABLE) || (target->GetType() == cmStateEnums::STATIC_LIBRARY) || (target->GetType() == cmStateEnums::SHARED_LIBRARY) || @@ -362,7 +371,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets( emitted.insert(target->GetName()); // for subdirs add a rule to build this specific target by name. - localName = cmStrCat(this->GetRelativeTargetDirectory(target), "/rule"); + localName = + cmStrCat(this->GetRelativeTargetDirectory(target.get()), "/rule"); commands.clear(); depends.clear(); @@ -383,11 +393,11 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets( } // Add a fast rule to build the target - std::string makefileName = - cmStrCat(this->GetRelativeTargetDirectory(target), "/build.make"); + std::string makefileName = cmStrCat( + this->GetRelativeTargetDirectory(target.get()), "/build.make"); // make sure the makefile name is suitable for a makefile std::string makeTargetName = - cmStrCat(this->GetRelativeTargetDirectory(target), "/build"); + cmStrCat(this->GetRelativeTargetDirectory(target.get()), "/build"); localName = cmStrCat(target->GetName(), "/fast"); depends.clear(); commands.clear(); @@ -400,9 +410,9 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets( // Add a local name for the rule to relink the target before // installation. - if (target->NeedRelinkBeforeInstall(this->ConfigName)) { - makeTargetName = - cmStrCat(this->GetRelativeTargetDirectory(target), "/preinstall"); + if (target->NeedRelinkBeforeInstall(this->GetConfigName())) { + makeTargetName = cmStrCat( + this->GetRelativeTargetDirectory(target.get()), "/preinstall"); localName = cmStrCat(target->GetName(), "/preinstall"); depends.clear(); commands.clear(); @@ -628,7 +638,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( << "# The command to remove a file.\n" << "RM = " << cmakeShellCommand - << " -E remove -f\n" + << " -E rm -f\n" << "\n"; makefileStream << "# Escaping for special characters.\n" @@ -673,9 +683,15 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsTop( if (!this->IsNMake() && !this->IsWatcomWMake() && !this->BorlandMakeCurlyHack) { // turn off RCS and SCCS automatic stuff from gmake - makefileStream - << "# Remove some rules from gmake that .SUFFIXES does not remove.\n" - << "SUFFIXES =\n\n"; + constexpr const char* vcs_rules[] = { + "%,v", "RCS/%", "RCS/%,v", "SCCS/s.%", "s.%", + }; + for (auto vcs_rule : vcs_rules) { + std::vector<std::string> vcs_depend; + vcs_depend.emplace_back(vcs_rule); + this->WriteMakeRule(makefileStream, "Disable VCS-based implicit rules.", + "%", vcs_depend, no_commands, false); + } } // Add a fake suffix to keep HP happy. Must be max 32 chars for SGI make. std::vector<std::string> depends; @@ -849,7 +865,7 @@ void cmLocalUnixMakefileGenerator3::AppendRuleDepends( // Add a dependency on the rule file itself unless an option to skip // it is specifically enabled by the user or project. if (!this->Makefile->IsOn("CMAKE_SKIP_RULE_DEPENDENCY")) { - cmAppend(depends, ruleFiles); + cm::append(depends, ruleFiles); } } @@ -857,7 +873,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomDepends( std::vector<std::string>& depends, const std::vector<cmCustomCommand>& ccs) { for (cmCustomCommand const& cc : ccs) { - cmCustomCommandGenerator ccg(cc, this->ConfigName, this); + cmCustomCommandGenerator ccg(cc, this->GetConfigName(), this); this->AppendCustomDepend(depends, ccg); } } @@ -868,7 +884,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomDepend( for (std::string const& d : ccg.GetDepends()) { // Lookup the real name of the dependency in case it is a CMake target. std::string dep; - if (this->GetRealDependency(d, this->ConfigName, dep)) { + if (this->GetRealDependency(d, this->GetConfigName(), dep)) { depends.push_back(std::move(dep)); } } @@ -879,7 +895,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommands( cmGeneratorTarget* target, std::string const& relative) { for (cmCustomCommand const& cc : ccs) { - cmCustomCommandGenerator ccg(cc, this->ConfigName, this); + cmCustomCommandGenerator ccg(cc, this->GetConfigName(), this); this->AppendCustomCommand(commands, ccg, target, relative, true); } } @@ -1022,7 +1038,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( this->CreateCDCommand(commands1, dir, relative); // push back the custom commands - cmAppend(commands, commands1); + cm::append(commands, commands1); } void cmLocalUnixMakefileGenerator3::AppendCleanCommand( @@ -1093,8 +1109,7 @@ void cmLocalUnixMakefileGenerator3::AppendDirectoryCleanCommand( return; } - cmLocalGenerator* rootLG = - this->GetGlobalGenerator()->GetLocalGenerators().at(0); + const auto& rootLG = this->GetGlobalGenerator()->GetLocalGenerators().at(0); std::string const& binaryDir = rootLG->GetCurrentBinaryDirectory(); std::string const& currentBinaryDir = this->GetCurrentBinaryDirectory(); std::string cleanfile = @@ -1551,8 +1566,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( this->WriteDivider(ruleFileStream); ruleFileStream << "# Targets provided globally by CMake.\n" << "\n"; - const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets(); - for (cmGeneratorTarget* gt : targets) { + const auto& targets = this->GetGeneratorTargets(); + for (const auto& gt : targets) { if (gt->GetType() == cmStateEnums::GLOBAL_TARGET) { std::string targetString = "Special rule for the target " + gt->GetName(); @@ -1564,8 +1579,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( text = "Running external command ..."; } depends.reserve(gt->GetUtilities().size()); - for (BT<std::string> const& u : gt->GetUtilities()) { - depends.push_back(u.Value); + for (BT<std::pair<std::string, bool>> const& u : gt->GetUtilities()) { + depends.push_back(u.Value.first); } this->AppendEcho(commands, text, cmLocalUnixMakefileGenerator3::EchoGlobal); @@ -1573,10 +1588,10 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( // Global targets store their rules in pre- and post-build commands. this->AppendCustomDepends(depends, gt->GetPreBuildCommands()); this->AppendCustomDepends(depends, gt->GetPostBuildCommands()); - this->AppendCustomCommands(commands, gt->GetPreBuildCommands(), gt, - this->GetCurrentBinaryDirectory()); - this->AppendCustomCommands(commands, gt->GetPostBuildCommands(), gt, + this->AppendCustomCommands(commands, gt->GetPreBuildCommands(), gt.get(), this->GetCurrentBinaryDirectory()); + this->AppendCustomCommands(commands, gt->GetPostBuildCommands(), + gt.get(), this->GetCurrentBinaryDirectory()); std::string targetName = gt->GetName(); this->WriteMakeRule(ruleFileStream, targetString.c_str(), targetName, depends, commands, true); @@ -1839,7 +1854,7 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( // Build a list of preprocessor definitions for the target. std::set<std::string> defines; - this->GetTargetDefines(target, this->ConfigName, implicitLang.first, + this->GetTargetDefines(target, this->GetConfigName(), implicitLang.first, defines); if (!defines.empty()) { /* clang-format off */ @@ -1863,11 +1878,11 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( std::vector<std::string> includes; this->GetIncludeDirectories(includes, target, implicitLang.first, - this->ConfigName); + this->GetConfigName()); std::string binaryDir = this->GetState()->GetBinaryDirectory(); if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) { std::string const& sourceDir = this->GetState()->GetSourceDirectory(); - cmEraseIf(includes, ::NotInProjectDir(sourceDir, binaryDir)); + cm::erase_if(includes, ::NotInProjectDir(sourceDir, binaryDir)); } for (std::string const& include : includes) { cmakefileStream << " \"" @@ -1957,18 +1972,18 @@ void cmLocalUnixMakefileGenerator3::WriteDivider(std::ostream& os) } void cmLocalUnixMakefileGenerator3::WriteCMakeArgument(std::ostream& os, - const char* s) + const std::string& s) { // Write the given string to the stream with escaping to get it back // into CMake through the lexical scanner. os << "\""; - for (const char* c = s; *c; ++c) { - if (*c == '\\') { + for (char c : s) { + if (c == '\\') { os << "\\\\"; - } else if (*c == '"') { + } else if (c == '"') { os << "\\\""; } else { - os << *c; + os << c; } } os << "\""; diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index f12ae8b..68eeb29 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -33,6 +33,8 @@ public: cmLocalUnixMakefileGenerator3(cmGlobalGenerator* gg, cmMakefile* mf); ~cmLocalUnixMakefileGenerator3() override; + std::string GetConfigName() const; + void ComputeHomeRelativeOutputPath() override; /** @@ -75,7 +77,7 @@ public: void SetBorlandMakeCurlyHack(bool b) { this->BorlandMakeCurlyHack = b; } // used in writing out Cmake files such as WriteDirectoryInformation - static void WriteCMakeArgument(std::ostream& os, const char* s); + static void WriteCMakeArgument(std::ostream& os, const std::string& s); /** creates the common disclaimer text at the top of each makefile */ void WriteDisclaimer(std::ostream& os); diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx index f3d828b..02e2c6d 100644 --- a/Source/cmLocalVisualStudio10Generator.cxx +++ b/Source/cmLocalVisualStudio10Generator.cxx @@ -2,8 +2,11 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmLocalVisualStudio10Generator.h" +#include <cmext/algorithm> + #include "cm_expat.h" +#include "cmAlgorithms.h" #include "cmGeneratorTarget.h" #include "cmGlobalVisualStudio10Generator.h" #include "cmMakefile.h" @@ -101,10 +104,11 @@ void cmLocalVisualStudio10Generator::GenerateTargetsDepthFirst( void cmLocalVisualStudio10Generator::Generate() { - std::vector<cmGeneratorTarget*> remaining = this->GetGeneratorTargets(); + std::vector<cmGeneratorTarget*> remaining; + cm::append(remaining, this->GetGeneratorTargets()); for (auto& t : remaining) { if (t) { - GenerateTargetsDepthFirst(t, remaining); + this->GenerateTargetsDepthFirst(t, remaining); } } this->WriteStampFiles(); @@ -124,8 +128,7 @@ void cmLocalVisualStudio10Generator::ReadAndStoreExternalGUID( std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE"); // save the GUID in the cache this->GlobalGenerator->GetCMakeInstance()->AddCacheEntry( - guidStoreName.c_str(), parser.GUID.c_str(), "Stored GUID", - cmStateEnums::INTERNAL); + guidStoreName, parser.GUID.c_str(), "Stored GUID", cmStateEnums::INTERNAL); } const char* cmLocalVisualStudio10Generator::ReportErrorLabel() const diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index e771a4a..74219b5 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmLocalVisualStudio7Generator.h" +#include <cm/memory> + #include <windows.h> #include <ctype.h> // for isspace @@ -52,20 +54,17 @@ extern cmVS7FlagTable cmLocalVisualStudio7GeneratorFlagTable[]; cmLocalVisualStudio7Generator::cmLocalVisualStudio7Generator( cmGlobalGenerator* gg, cmMakefile* mf) : cmLocalVisualStudioGenerator(gg, mf) + , Internal(cm::make_unique<cmLocalVisualStudio7GeneratorInternals>(this)) { - this->Internal = new cmLocalVisualStudio7GeneratorInternals(this); } -cmLocalVisualStudio7Generator::~cmLocalVisualStudio7Generator() -{ - delete this->Internal; -} +cmLocalVisualStudio7Generator::~cmLocalVisualStudio7Generator() = default; void cmLocalVisualStudio7Generator::AddHelperCommands() { // Now create GUIDs for targets - const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets(); - for (cmGeneratorTarget const* l : tgts) { + const auto& tgts = this->GetGeneratorTargets(); + for (const auto& l : tgts) { if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } @@ -89,8 +88,8 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets() // Visual Studio .NET 2003 Service Pack 1 will not run post-build // commands for targets in which no sources are built. Add dummy // rules to force these targets to build. - const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets(); - for (cmGeneratorTarget* l : tgts) { + const auto& tgts = this->GetGeneratorTargets(); + for (auto& l : tgts) { if (l->GetType() == cmStateEnums::GLOBAL_TARGET) { std::vector<std::string> no_depends; cmCustomCommandLines force_commands = @@ -102,9 +101,9 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets() this->Makefile->GetOrCreateGeneratedSource(force)) { sf->SetProperty("SYMBOLIC", "1"); } - if (cmSourceFile* file = this->Makefile->AddCustomCommandToOutput( - force.c_str(), no_depends, no_main_dependency, force_commands, " ", - 0, true)) { + if (cmSourceFile* file = this->AddCustomCommandToOutput( + force, no_depends, no_main_dependency, force_commands, " ", + nullptr, true)) { l->AddSource(file->ResolveFullPath()); } } @@ -125,17 +124,17 @@ void cmLocalVisualStudio7Generator::WriteProjectFiles() } // Get the set of targets in this directory. - const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets(); + const auto& tgts = this->GetGeneratorTargets(); // Create the project file for each target. - for (cmGeneratorTarget* l : tgts) { + for (const auto& l : tgts) { if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } // INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace // so don't build a projectfile for it if (!l->GetProperty("EXTERNAL_MSPROJECT")) { - this->CreateSingleVCProj(l->GetName(), l); + this->CreateSingleVCProj(l->GetName(), l.get()); } } } @@ -146,7 +145,7 @@ void cmLocalVisualStudio7Generator::WriteStampFiles() // out of date. std::string stampName = cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles"); - cmSystemTools::MakeDirectory(stampName.c_str()); + cmSystemTools::MakeDirectory(stampName); stampName += "/generate.stamp"; cmsys::ofstream stamp(stampName.c_str()); stamp << "# CMake generation timestamp file for this directory.\n"; @@ -194,7 +193,7 @@ void cmLocalVisualStudio7Generator::CreateSingleVCProj( } // add to the list of projects - target->Target->SetProperty("GENERATOR_FILE_NAME", lname.c_str()); + target->Target->SetProperty("GENERATOR_FILE_NAME", lname); // create the dsp.cmake file std::string fname; fname = cmStrCat(this->GetCurrentBinaryDirectory(), '/', lname); @@ -257,12 +256,11 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() "--check-stamp-file", stampName }); std::string comment = cmStrCat("Building Custom Rule ", makefileIn); const char* no_working_directory = nullptr; - std::string fullpathStampName = - cmSystemTools::CollapseFullPath(stampName.c_str()); - this->Makefile->AddCustomCommandToOutput( - fullpathStampName, listFiles, makefileIn, commandLines, comment.c_str(), - no_working_directory, true, false); - if (cmSourceFile* file = this->Makefile->GetSource(makefileIn.c_str())) { + std::string fullpathStampName = cmSystemTools::CollapseFullPath(stampName); + this->AddCustomCommandToOutput(fullpathStampName, listFiles, makefileIn, + commandLines, comment.c_str(), + no_working_directory, true, false); + if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) { // Finalize the source file path now since we're adding this after // the generator validated all project-named sources. file->ResolveFullPath(); @@ -279,7 +277,7 @@ void cmLocalVisualStudio7Generator::WriteConfigurations( { fout << "\t<Configurations>\n"; for (std::string const& config : configs) { - this->WriteConfiguration(fout, config.c_str(), libName, target); + this->WriteConfiguration(fout, config, libName, target); } fout << "\t</Configurations>\n"; } @@ -580,7 +578,7 @@ public: this->Stream << this->LG->EscapeForXML("\n"); } std::string script = this->LG->ConstructScript(ccg); - this->Stream << this->LG->EscapeForXML(script.c_str()); + this->Stream << this->LG->EscapeForXML(script); } private: @@ -733,13 +731,13 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( : target->GetDirectory(configName); /* clang-format off */ fout << "\t\t\tOutputDirectory=\"" - << this->ConvertToXMLOutputPathSingle(outDir.c_str()) << "\"\n"; + << this->ConvertToXMLOutputPathSingle(outDir) << "\"\n"; /* clang-format on */ } /* clang-format off */ fout << "\t\t\tIntermediateDirectory=\"" - << this->ConvertToXMLOutputPath(intermediateDir.c_str()) + << this->ConvertToXMLOutputPath(intermediateDir) << "\"\n" << "\t\t\tConfigurationType=\"" << configType << "\"\n" << "\t\t\tUseOfMFC=\"" << mfcFlag << "\"\n" @@ -788,8 +786,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( } else { modDir = "."; } - fout << "\t\t\t\tModulePath=\"" - << this->ConvertToXMLOutputPath(modDir.c_str()) + fout << "\t\t\t\tModulePath=\"" << this->ConvertToXMLOutputPath(modDir) << "\\$(ConfigurationName)\"\n"; } targetOptions.OutputAdditionalIncludeDirectories( @@ -802,7 +799,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( std::string pdb = target->GetCompilePDBPath(configName); if (!pdb.empty()) { fout << "\t\t\t\tProgramDataBaseFileName=\"" - << this->ConvertToXMLOutputPathSingle(pdb.c_str()) << "\"\n"; + << this->ConvertToXMLOutputPathSingle(pdb) << "\"\n"; } } fout << "/>\n"; // end of <Tool Name=VCCLCompilerTool @@ -879,7 +876,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( fout << "\n\t\t\t\tAdditionalManifestFiles=\""; for (cmSourceFile const* manifest : manifest_srcs) { std::string m = manifest->GetFullPath(); - fout << this->ConvertToXMLOutputPath(m.c_str()) << ";"; + fout << this->ConvertToXMLOutputPath(m) << ";"; } fout << "\""; } @@ -946,7 +943,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( } std::string configTypeUpper = cmSystemTools::UpperCase(configName); std::string linkFlagsConfig = cmStrCat("LINK_FLAGS_", configTypeUpper); - targetLinkFlags = target->GetProperty(linkFlagsConfig.c_str()); + targetLinkFlags = target->GetProperty(linkFlagsConfig); if (targetLinkFlags) { extraLinkOptions += " "; extraLinkOptions += targetLinkFlags; @@ -985,7 +982,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( fout << "\t\t\t<Tool\n" << "\t\t\t\tName=\"" << tool << "\"\n"; fout << "\t\t\t\tOutputFile=\"" - << this->ConvertToXMLOutputPathSingle(libpath.c_str()) << "\"/>\n"; + << this->ConvertToXMLOutputPathSingle(libpath) << "\"/>\n"; break; } case cmStateEnums::STATIC_LIBRARY: { @@ -1015,7 +1012,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( fout << "\t\t\t\tAdditionalOptions=\"" << libflags << "\"\n"; } fout << "\t\t\t\tOutputFile=\"" - << this->ConvertToXMLOutputPathSingle(libpath.c_str()) << "\"/>\n"; + << this->ConvertToXMLOutputPathSingle(libpath) << "\"/>\n"; break; } case cmStateEnums::SHARED_LIBRARY: @@ -1057,7 +1054,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( temp = cmStrCat(target->GetDirectory(configName), '/', targetNames.Output); fout << "\t\t\t\tOutputFile=\"" - << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n"; + << this->ConvertToXMLOutputPathSingle(temp) << "\"\n"; this->WriteTargetVersionAttribute(fout, target); linkOptions.OutputFlagMap(fout, 4); fout << "\t\t\t\tAdditionalLibraryDirectories=\""; @@ -1066,7 +1063,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( temp = cmStrCat(target->GetPDBDirectory(configName), '/', targetNames.PDB); fout << "\t\t\t\tProgramDatabaseFile=\"" - << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n"; + << this->ConvertToXMLOutputPathSingle(temp) << "\"\n"; if (targetOptions.IsDebug()) { fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n"; } @@ -1078,7 +1075,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( } } std::string stackVar = cmStrCat("CMAKE_", linkLanguage, "_STACK_SIZE"); - const char* stackVal = this->Makefile->GetDefinition(stackVar.c_str()); + const char* stackVal = this->Makefile->GetDefinition(stackVar); if (stackVal) { fout << "\t\t\t\tStackReserveSize=\"" << stackVal << "\"\n"; } @@ -1086,7 +1083,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact), '/', targetNames.ImportLibrary); fout << "\t\t\t\tImportLibrary=\"" - << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\""; + << this->ConvertToXMLOutputPathSingle(temp) << "\""; if (this->FortranProject) { fout << "\n\t\t\t\tLinkDLL=\"true\""; } @@ -1132,14 +1129,14 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( temp = cmStrCat(target->GetDirectory(configName), '/', targetNames.Output); fout << "\t\t\t\tOutputFile=\"" - << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n"; + << this->ConvertToXMLOutputPathSingle(temp) << "\"\n"; this->WriteTargetVersionAttribute(fout, target); linkOptions.OutputFlagMap(fout, 4); fout << "\t\t\t\tAdditionalLibraryDirectories=\""; this->OutputLibraryDirectories(fout, cli.GetDirectories()); fout << "\"\n"; std::string path = this->ConvertToXMLOutputPathSingle( - target->GetPDBDirectory(configName).c_str()); + target->GetPDBDirectory(configName)); fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/" << targetNames.PDB << "\"\n"; if (targetOptions.IsDebug()) { @@ -1167,7 +1164,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( << "\"\n"; } std::string stackVar = cmStrCat("CMAKE_", linkLanguage, "_STACK_SIZE"); - const char* stackVal = this->Makefile->GetDefinition(stackVar.c_str()); + const char* stackVal = this->Makefile->GetDefinition(stackVar); if (stackVal) { fout << "\t\t\t\tStackReserveSize=\"" << stackVal << "\""; } @@ -1175,7 +1172,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact), '/', targetNames.ImportLibrary); fout << "\t\t\t\tImportLibrary=\"" - << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"/>\n"; + << this->ConvertToXMLOutputPathSingle(temp) << "\"/>\n"; break; } case cmStateEnums::UTILITY: @@ -1256,8 +1253,8 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries( for (auto const& lib : libs) { if (lib.IsPath) { std::string rel = - lg->MaybeConvertToRelativePath(currentBinDir, lib.Value.Value.c_str()); - fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " "; + lg->MaybeConvertToRelativePath(currentBinDir, lib.Value.Value); + fout << lg->ConvertToXMLOutputPath(rel) << " "; } else if (!lib.Target || lib.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { fout << lib.Value.Value << " "; @@ -1282,7 +1279,7 @@ void cmLocalVisualStudio7GeneratorInternals::OutputObjects( if (!obj->GetObjectLibrary().empty()) { std::string const& objFile = obj->GetFullPath(); std::string rel = lg->MaybeConvertToRelativePath(currentBinDir, objFile); - fout << sep << lg->ConvertToXMLOutputPath(rel.c_str()); + fout << sep << lg->ConvertToXMLOutputPath(rel); sep = " "; } } @@ -1303,9 +1300,8 @@ void cmLocalVisualStudio7Generator::OutputLibraryDirectories( } // Switch to a relative path specification if it is shorter. - if (cmSystemTools::FileIsFullPath(dir.c_str())) { - std::string rel = - this->MaybeConvertToRelativePath(currentBinDir, dir.c_str()); + if (cmSystemTools::FileIsFullPath(dir)) { + std::string rel = this->MaybeConvertToRelativePath(currentBinDir, dir); if (rel.size() < dir.size()) { dir = rel; } @@ -1314,9 +1310,8 @@ void cmLocalVisualStudio7Generator::OutputLibraryDirectories( // First search a configuration-specific subdirectory and then the // original directory. fout << comma - << this->ConvertToXMLOutputPath( - (dir + "/$(ConfigurationName)").c_str()) - << "," << this->ConvertToXMLOutputPath(dir.c_str()); + << this->ConvertToXMLOutputPath(dir + "/$(ConfigurationName)") << "," + << this->ConvertToXMLOutputPath(dir); comma = ","; } } @@ -1337,7 +1332,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, // Add CMakeLists.txt file with rule to re-run CMake for user convenience. if (target->GetType() != cmStateEnums::GLOBAL_TARGET && target->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { - if (cmSourceFile const* sf = this->CreateVCProjBuildRule()) { + if (cmSourceFile* sf = this->CreateVCProjBuildRule()) { cmGeneratorTarget::AllConfigSource acs; acs.Source = sf; acs.Kind = cmGeneratorTarget::SourceKindCustomCommand; @@ -1515,16 +1510,15 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( if (const char* deps = sf.GetProperty("OBJECT_DEPENDS")) { std::vector<std::string> depends = cmExpandedList(deps); const char* sep = ""; - for (std::vector<std::string>::iterator j = depends.begin(); - j != depends.end(); ++j) { + for (const std::string& d : depends) { fc.AdditionalDeps += sep; - fc.AdditionalDeps += lg->ConvertToXMLOutputPath(j->c_str()); + fc.AdditionalDeps += lg->ConvertToXMLOutputPath(d); sep = ";"; needfc = true; } } - const std::string& linkLanguage = gt->GetLinkerLanguage(config.c_str()); + const std::string& linkLanguage = gt->GetLinkerLanguage(config); // If HEADER_FILE_ONLY is set, we must suppress this generation in // the project file fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") || @@ -1629,7 +1623,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup( FCInfo fcinfo(this, target, acs, configs); fout << "\t\t\t<File\n"; - std::string d = this->ConvertToXMLOutputPathSingle(source.c_str()); + std::string d = this->ConvertToXMLOutputPathSingle(source); // Tell MS-Dev what the source is. If the compiler knows how to // build it, then it will. fout << "\t\t\t\tRelativePath=\"" << d << "\">\n"; @@ -1759,21 +1753,21 @@ void cmLocalVisualStudio7Generator::WriteCustomRule( fout << "\t\t\t\t\t<Tool\n" << "\t\t\t\t\tName=\"" << compileTool << "\"\n" << "\t\t\t\t\tAdditionalOptions=\"" - << this->EscapeForXML(fc.CompileFlags.c_str()) << "\"/>\n"; + << this->EscapeForXML(fc.CompileFlags) << "\"/>\n"; } std::string comment = this->ConstructComment(ccg); std::string script = this->ConstructScript(ccg); if (this->FortranProject) { - cmSystemTools::ReplaceString(script, "$(Configuration)", config.c_str()); + cmSystemTools::ReplaceString(script, "$(Configuration)", config); } /* clang-format off */ fout << "\t\t\t\t\t<Tool\n" << "\t\t\t\t\tName=\"" << customTool << "\"\n" << "\t\t\t\t\tDescription=\"" - << this->EscapeForXML(comment.c_str()) << "\"\n" + << this->EscapeForXML(comment) << "\"\n" << "\t\t\t\t\tCommandLine=\"" - << this->EscapeForXML(script.c_str()) << "\"\n" + << this->EscapeForXML(script) << "\"\n" << "\t\t\t\t\tAdditionalDependencies=\""; /* clang-format on */ if (ccg.GetDepends().empty()) { @@ -1789,8 +1783,8 @@ void cmLocalVisualStudio7Generator::WriteCustomRule( for (std::string const& d : ccg.GetDepends()) { // Get the real name of the dependency in case it is a CMake target. std::string dep; - if (this->GetRealDependency(d.c_str(), config.c_str(), dep)) { - fout << this->ConvertToXMLOutputPath(dep.c_str()) << ";"; + if (this->GetRealDependency(d, config, dep)) { + fout << this->ConvertToXMLOutputPath(dep) << ";"; } } } @@ -1802,7 +1796,7 @@ void cmLocalVisualStudio7Generator::WriteCustomRule( // Write a rule for the output generated by this command. const char* sep = ""; for (std::string const& output : ccg.GetOutputs()) { - fout << sep << this->ConvertToXMLOutputPathSingle(output.c_str()); + fout << sep << this->ConvertToXMLOutputPathSingle(output); sep = ";"; } } @@ -1948,7 +1942,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStartFortran( this->WriteProjectSCC(fout, target); /* clang-format off */ fout<< "\tKeyword=\"" << keyword << "\">\n" - << "\tProjectGUID=\"{" << gg->GetGUID(libName.c_str()) << "}\">\n" + << "\tProjectGUID=\"{" << gg->GetGUID(libName) << "}\">\n" << "\t<Platforms>\n" << "\t\t<Platform\n\t\t\tName=\"" << gg->GetPlatformName() << "\"/>\n" << "\t</Platforms>\n"; @@ -1983,7 +1977,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStart( keyword = "Win32Proj"; } fout << "\tName=\"" << projLabel << "\"\n"; - fout << "\tProjectGUID=\"{" << gg->GetGUID(libName.c_str()) << "}\"\n"; + fout << "\tProjectGUID=\"{" << gg->GetGUID(libName) << "}\"\n"; this->WriteProjectSCC(fout, target); if (const char* targetFrameworkVersion = target->GetProperty("VS_DOTNET_TARGET_FRAMEWORK_VERSION")) { @@ -2037,7 +2031,7 @@ std::string cmLocalVisualStudio7Generator::EscapeForXML(const std::string& s) } std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPath( - const char* path) + const std::string& path) { std::string ret = this->ConvertToOutputFormat(path, cmOutputConverter::SHELL); @@ -2049,7 +2043,7 @@ std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPath( } std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPathSingle( - const char* path) + const std::string& path) { std::string ret = this->ConvertToOutputFormat(path, cmOutputConverter::SHELL); @@ -2061,7 +2055,7 @@ std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPathSingle( } void cmVS7GeneratorOptions::OutputFlag(std::ostream& fout, int indent, - const char* flag, + const std::string& flag, const std::string& content) { fout.fill('\t'); @@ -2130,8 +2124,7 @@ void cmLocalVisualStudio7Generator::ReadAndStoreExternalGUID( std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE"); // save the GUID in the cache this->GlobalGenerator->GetCMakeInstance()->AddCacheEntry( - guidStoreName.c_str(), parser.GUID.c_str(), "Stored GUID", - cmStateEnums::INTERNAL); + guidStoreName, parser.GUID.c_str(), "Stored GUID", cmStateEnums::INTERNAL); } std::string cmLocalVisualStudio7Generator::GetTargetDirectory( diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 671783f..8b9b8ad 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <memory> #include <string> #include <vector> @@ -30,7 +31,7 @@ public: : cmVisualStudioGeneratorOptions(lg, tool, table, extraTable) { } - void OutputFlag(std::ostream& fout, int indent, const char* tag, + void OutputFlag(std::ostream& fout, int indent, const std::string& tag, const std::string& content) override; }; @@ -48,6 +49,10 @@ public: virtual ~cmLocalVisualStudio7Generator(); + cmLocalVisualStudio7Generator(const cmLocalVisualStudio7Generator&) = delete; + const cmLocalVisualStudio7Generator& operator=( + const cmLocalVisualStudio7Generator&) = delete; + void AddHelperCommands() override; /** @@ -101,8 +106,8 @@ private: void WriteConfiguration(std::ostream& fout, const std::string& configName, const std::string& libName, cmGeneratorTarget* tgt); std::string EscapeForXML(const std::string& s); - std::string ConvertToXMLOutputPath(const char* path); - std::string ConvertToXMLOutputPathSingle(const char* path); + std::string ConvertToXMLOutputPath(const std::string& path); + std::string ConvertToXMLOutputPathSingle(const std::string& path); void OutputTargetRules(std::ostream& fout, const std::string& configName, cmGeneratorTarget* target, const std::string& libName); @@ -144,7 +149,7 @@ private: bool FortranProject; bool WindowsCEProject; - cmLocalVisualStudio7GeneratorInternals* Internal; + std::unique_ptr<cmLocalVisualStudio7GeneratorInternals> Internal; }; #endif diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index 336e3a5..8d50898 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -104,8 +104,8 @@ cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmGeneratorTarget* target, std::vector<std::string> no_depends; cmCustomCommandLines commands = cmMakeSingleCommandLine( { cmSystemTools::GetCMakeCommand(), "-E", "make_directory", impDir }); - pcc.reset(new cmCustomCommand(0, no_output, no_byproducts, no_depends, - commands, 0, 0)); + pcc.reset(new cmCustomCommand(no_output, no_byproducts, no_depends, commands, + cmListFileBacktrace(), nullptr, nullptr)); pcc->SetEscapeOldStyle(false); pcc->SetEscapeAllowMakeVars(true); return pcc; diff --git a/Source/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx index 5a06d4a..ac0d35e 100644 --- a/Source/cmLocalXCodeGenerator.cxx +++ b/Source/cmLocalXCodeGenerator.cxx @@ -40,7 +40,7 @@ void cmLocalXCodeGenerator::Generate() { cmLocalGenerator::Generate(); - for (auto target : this->GetGeneratorTargets()) { + for (const auto& target : this->GetGeneratorTargets()) { target->HasMacOSXRpathInstallNameDir(""); } } @@ -49,7 +49,7 @@ void cmLocalXCodeGenerator::GenerateInstallRules() { cmLocalGenerator::GenerateInstallRules(); - for (auto target : this->GetGeneratorTargets()) { + for (const auto& target : this->GetGeneratorTargets()) { target->HasMacOSXRpathInstallNameDir(""); } } diff --git a/Source/cmMachO.cxx b/Source/cmMachO.cxx index 6cbed36..53112e0 100644 --- a/Source/cmMachO.cxx +++ b/Source/cmMachO.cxx @@ -79,14 +79,14 @@ public: // A load_command and its associated data struct RawLoadCommand { - uint32_t type(const cmMachOHeaderAndLoadCommands* m) const + uint32_t type(const cmMachOHeaderAndLoadCommands& m) const { if (this->LoadCommand.size() < sizeof(load_command)) { return 0; } const load_command* cmd = reinterpret_cast<const load_command*>(&this->LoadCommand[0]); - return m->swap(cmd->cmd); + return m.swap(cmd->cmd); } std::vector<char> LoadCommand; }; @@ -186,8 +186,11 @@ class cmMachOInternal { public: cmMachOInternal(const char* fname); + cmMachOInternal(const cmMachOInternal&) = delete; ~cmMachOInternal(); + cmMachOInternal& operator=(const cmMachOInternal&) = delete; + // read a Mach-O file bool read_mach_o(uint32_t file_offset); @@ -202,7 +205,7 @@ public: std::string ErrorMessage; // the list of Mach-O's - std::vector<cmMachOHeaderAndLoadCommands*> MachOList; + std::vector<std::unique_ptr<cmMachOHeaderAndLoadCommands>> MachOList; }; cmMachOInternal::cmMachOInternal(const char* fname) @@ -260,12 +263,7 @@ cmMachOInternal::cmMachOInternal(const char* fname) } } -cmMachOInternal::~cmMachOInternal() -{ - for (auto& i : this->MachOList) { - delete i; - } -} +cmMachOInternal::~cmMachOInternal() = default; bool cmMachOInternal::read_mach_o(uint32_t file_offset) { @@ -280,25 +278,25 @@ bool cmMachOInternal::read_mach_o(uint32_t file_offset) return false; } - cmMachOHeaderAndLoadCommands* f = nullptr; + std::unique_ptr<cmMachOHeaderAndLoadCommands> f; if (magic == MH_CIGAM || magic == MH_MAGIC) { bool swap = false; if (magic == MH_CIGAM) { swap = true; } - f = new cmMachOHeaderAndLoadCommandsImpl<mach_header>(swap); + f = cm::make_unique<cmMachOHeaderAndLoadCommandsImpl<mach_header>>(swap); } else if (magic == MH_CIGAM_64 || magic == MH_MAGIC_64) { bool swap = false; if (magic == MH_CIGAM_64) { swap = true; } - f = new cmMachOHeaderAndLoadCommandsImpl<mach_header_64>(swap); + f = + cm::make_unique<cmMachOHeaderAndLoadCommandsImpl<mach_header_64>>(swap); } if (f && f->read_mach_o(this->Fin)) { - this->MachOList.push_back(f); + this->MachOList.push_back(std::move(f)); } else { - delete f; this->ErrorMessage = "Failed to read Mach-O header."; return false; } @@ -333,11 +331,12 @@ bool cmMachO::GetInstallName(std::string& install_name) } // grab the first Mach-O and get the install name from that one - cmMachOHeaderAndLoadCommands* macho = this->Internal->MachOList[0]; + std::unique_ptr<cmMachOHeaderAndLoadCommands>& macho = + this->Internal->MachOList[0]; for (size_t i = 0; i < macho->load_commands().size(); i++) { const cmMachOHeaderAndLoadCommands::RawLoadCommand& cmd = macho->load_commands()[i]; - uint32_t lc_cmd = cmd.type(macho); + uint32_t lc_cmd = cmd.type(*macho); if (lc_cmd == LC_ID_DYLIB || lc_cmd == LC_LOAD_WEAK_DYLIB || lc_cmd == LC_LOAD_DYLIB) { if (sizeof(dylib_command) < cmd.LoadCommand.size()) { diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index ba9947a..0b0d9ac 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -7,10 +7,10 @@ #include <cm/memory> #include <cm/string_view> +#include <cmext/algorithm> #include "cm_static_string_view.hxx" -#include "cmAlgorithms.h" #include "cmExecutionStatus.h" #include "cmFunctionBlocker.h" #include "cmListFileCache.h" @@ -167,7 +167,7 @@ bool cmMacroFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, cmExecutionStatus& status) { cmMakefile& mf = status.GetMakefile(); - mf.AppendProperty("MACROS", this->Args[0].c_str()); + mf.AppendProperty("MACROS", this->Args[0]); // create a new command and add it to cmake cmMacroHelperCommand f; f.Args = this->Args; @@ -190,7 +190,7 @@ bool cmMacroCommand(std::vector<std::string> const& args, // create a function blocker { auto fb = cm::make_unique<cmMacroFunctionBlocker>(); - cmAppend(fb->Args, args); + cm::append(fb->Args, args); status.GetMakefile().AddFunctionBlocker(std::move(fb)); } return true; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index f143ef7..94d99b7 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -15,10 +15,15 @@ #include <cm/iterator> #include <cm/memory> +#include <cm/optional> +#include <cm/vector> +#include <cmext/algorithm> #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" +#include "cm_jsoncpp_value.h" +#include "cm_jsoncpp_writer.h" #include "cm_sys_stat.h" #include "cmAlgorithms.h" @@ -36,6 +41,7 @@ #include "cmInstallGenerator.h" // IWYU pragma: keep #include "cmInstallSubdirectoryGenerator.h" #include "cmListFileCache.h" +#include "cmLocalGenerator.h" #include "cmMessageType.h" #include "cmRange.h" #include "cmSourceFile.h" @@ -117,15 +123,7 @@ cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator, #endif } -cmMakefile::~cmMakefile() -{ - cmDeleteAll(this->InstallGenerators); - cmDeleteAll(this->TestGenerators); - cmDeleteAll(this->SourceFiles); - cmDeleteAll(this->Tests); - cmDeleteAll(this->ImportedTargetsOwned); - cmDeleteAll(this->EvaluationFiles); -} +cmMakefile::~cmMakefile() = default; cmDirectoryId cmMakefile::GetDirectoryId() const { @@ -133,7 +131,7 @@ cmDirectoryId cmMakefile::GetDirectoryId() const // If we ever need to expose this to CMake language code we should // add a read-only property in cmMakefile::GetProperty. char buf[32]; - sprintf(buf, "<%p>", + sprintf(buf, "(%p)", static_cast<void const*>(this)); // cast avoids format warning return std::string(buf); } @@ -146,7 +144,7 @@ void cmMakefile::IssueMessage(MessageType t, std::string const& text) const this->ExecutionStatusStack.back()->SetNestedError(); } } - this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace()); + this->GetCMakeInstance()->IssueMessage(t, text, this->Backtrace); } bool cmMakefile::CheckCMP0037(std::string const& targetName, @@ -313,21 +311,54 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const } std::ostringstream msg; - msg << full_path << "(" << lff.Line << "): "; - msg << lff.Name.Original << "("; - bool expand = this->GetCMakeInstance()->GetTraceExpand(); + std::vector<std::string> args; std::string temp; + bool expand = this->GetCMakeInstance()->GetTraceExpand(); + + args.reserve(lff.Arguments.size()); for (cmListFileArgument const& arg : lff.Arguments) { if (expand) { temp = arg.Value; this->ExpandVariablesInString(temp); - msg << temp; + args.push_back(temp); } else { - msg << arg.Value; + args.push_back(arg.Value); + } + } + + switch (this->GetCMakeInstance()->GetTraceFormat()) { + case cmake::TraceFormat::TRACE_JSON_V1: { +#ifndef CMAKE_BOOTSTRAP + Json::Value val; + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + val["file"] = full_path; + val["line"] = static_cast<Json::Value::Int64>(lff.Line); + val["cmd"] = lff.Name.Original; + val["args"] = Json::Value(Json::arrayValue); + for (std::string const& arg : args) { + val["args"].append(arg); + } + val["time"] = cmSystemTools::GetTime(); + val["frame"] = + static_cast<Json::Value::UInt64>(this->ExecutionStatusStack.size()); + msg << Json::writeString(builder, val); +#endif + break; } - msg << " "; + case cmake::TraceFormat::TRACE_HUMAN: + msg << full_path << "(" << lff.Line << "): "; + msg << lff.Name.Original << "("; + + for (std::string const& arg : args) { + msg << arg << " "; + } + msg << ")"; + break; + case cmake::TraceFormat::TRACE_UNDEFINED: + msg << "INTERNAL ERROR: Trace format is TRACE_UNDEFINED"; + break; } - msg << ")"; auto& f = this->GetCMakeInstance()->GetTraceFile(); if (f) { @@ -653,6 +684,27 @@ bool cmMakefile::ReadListFile(const std::string& filename) return true; } +bool cmMakefile::ReadListFileAsString(const std::string& content, + const std::string& virtualFileName) +{ + std::string filenametoread = cmSystemTools::CollapseFullPath( + virtualFileName, this->GetCurrentSourceDirectory()); + + ListFileScope scope(this, filenametoread); + + cmListFile listFile; + if (!listFile.ParseString(content.c_str(), virtualFileName.c_str(), + this->GetMessenger(), this->Backtrace)) { + return false; + } + + this->ReadListFile(listFile, filenametoread); + if (cmSystemTools::GetFatalErrorOccured()) { + scope.Quiet(); + } + return true; +} + void cmMakefile::ReadListFile(cmListFile const& listFile, std::string const& filenametoread) { @@ -737,12 +789,13 @@ void cmMakefile::AddEvaluationFile( std::unique_ptr<cmCompiledGeneratorExpression> condition, bool inputIsContent) { - this->EvaluationFiles.push_back(new cmGeneratorExpressionEvaluationFile( - inputFile, std::move(outputName), std::move(condition), inputIsContent, - this->GetPolicyStatus(cmPolicies::CMP0070))); + this->EvaluationFiles.push_back( + cm::make_unique<cmGeneratorExpressionEvaluationFile>( + inputFile, std::move(outputName), std::move(condition), inputIsContent, + this->GetPolicyStatus(cmPolicies::CMP0070))); } -std::vector<cmGeneratorExpressionEvaluationFile*> +const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>& cmMakefile::GetEvaluationFiles() const { return this->EvaluationFiles; @@ -780,38 +833,42 @@ struct file_not_persistent }; } -void cmMakefile::AddFinalAction(FinalAction action) +void cmMakefile::AddGeneratorAction(GeneratorAction action) { - this->FinalActions.push_back(std::move(action)); + assert(!this->GeneratorActionsInvoked); + this->GeneratorActions.emplace_back(std::move(action), this->Backtrace); } -void cmMakefile::FinalPass() +void cmMakefile::DoGenerate(cmLocalGenerator& lg) { // do all the variable expansions here this->ExpandVariablesCMP0019(); // give all the commands a chance to do something // after the file has been parsed before generation - for (FinalAction& action : this->FinalActions) { - action(*this); + for (const BT<GeneratorAction>& action : this->GeneratorActions) { + action.Value(lg, action.Backtrace); } + this->GeneratorActionsInvoked = true; + this->DelayedOutputFiles.clear(); + this->DelayedOutputFilesHaveGenex = false; // go through all configured files and see which ones still exist. // we don't want cmake to re-run if a configured file is created and deleted // during processing as that would make it a transient file that can't // influence the build process - cmEraseIf(this->OutputFiles, file_not_persistent()); + cm::erase_if(this->OutputFiles, file_not_persistent()); // if a configured file is used as input for another configured file, // and then deleted it will show up in the input list files so we // need to scan those too - cmEraseIf(this->ListFiles, file_not_persistent()); + cm::erase_if(this->ListFiles, file_not_persistent()); } // Generate the output file -void cmMakefile::ConfigureFinalPass() +void cmMakefile::Generate(cmLocalGenerator& lg) { - this->FinalPass(); + this->DoGenerate(lg); const char* oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY"); if (oldValue && cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue, "2.4")) { @@ -825,6 +882,39 @@ void cmMakefile::ConfigureFinalPass() } } +namespace { +// There are still too many implicit backtraces through cmMakefile. As a +// workaround we reset the backtrace temporarily. +struct BacktraceGuard +{ + BacktraceGuard(cmListFileBacktrace& lfbt, cmListFileBacktrace current) + : Backtrace(lfbt) + , Previous(lfbt) + { + this->Backtrace = std::move(current); + } + + ~BacktraceGuard() { this->Backtrace = std::move(Previous); } + +private: + cmListFileBacktrace& Backtrace; + cmListFileBacktrace Previous; +}; + +cm::optional<std::string> MakeOptionalString(const char* str) +{ + if (str) { + return str; + } + return cm::nullopt; +} + +const char* GetCStrOrNull(const cm::optional<std::string>& str) +{ + return str ? str->c_str() : nullptr; +} +} + bool cmMakefile::ValidateCustomCommand( const cmCustomCommandLines& commandLines) const { @@ -842,7 +932,8 @@ bool cmMakefile::ValidateCustomCommand( } cmTarget* cmMakefile::GetCustomCommandTarget( - const std::string& target, cmObjectLibraryCommands objLibCommands) const + const std::string& target, cmObjectLibraryCommands objLibCommands, + const cmListFileBacktrace& lfbt) const { // Find the target to which to add the custom command. auto ti = this->Targets.find(target); @@ -876,7 +967,7 @@ cmTarget* cmMakefile::GetCustomCommandTarget( e << "No TARGET '" << target << "' has been created in this directory."; } - this->IssueMessage(messageType, e.str()); + this->GetCMakeInstance()->IssueMessage(messageType, e.str(), lfbt); } return nullptr; @@ -889,7 +980,8 @@ cmTarget* cmMakefile::GetCustomCommandTarget( e << "Target \"" << target << "\" is an OBJECT library " "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands."; - this->IssueMessage(MessageType::FATAL_ERROR, e.str()); + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(), + lfbt); return nullptr; } if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) { @@ -897,7 +989,8 @@ cmTarget* cmMakefile::GetCustomCommandTarget( e << "Target \"" << target << "\" is an INTERFACE library " "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands."; - this->IssueMessage(MessageType::FATAL_ERROR, e.str()); + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(), + lfbt); return nullptr; } @@ -910,9 +1003,10 @@ cmTarget* cmMakefile::AddCustomCommandToTarget( const cmCustomCommandLines& commandLines, cmCustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle, bool uses_terminal, const std::string& depfile, const std::string& job_pool, - bool command_expand_lists, cmObjectLibraryCommands objLibCommands) + bool command_expand_lists) { - cmTarget* t = this->GetCustomCommandTarget(target, objLibCommands); + cmTarget* t = this->GetCustomCommandTarget( + target, cmObjectLibraryCommands::Reject, this->Backtrace); // Validate custom commands. if (!t || !this->ValidateCustomCommand(commandLines)) { @@ -920,175 +1014,83 @@ cmTarget* cmMakefile::AddCustomCommandToTarget( } // Always create the byproduct sources and mark them generated. - this->CreateGeneratedSources(byproducts); - - this->CommitCustomCommandToTarget( - t, byproducts, depends, commandLines, type, comment, workingDir, - escapeOldStyle, uses_terminal, depfile, job_pool, command_expand_lists); + this->CreateGeneratedByproducts(byproducts); + + // Strings could be moved into the callback function with C++14. + cm::optional<std::string> commentStr = MakeOptionalString(comment); + cm::optional<std::string> workingStr = MakeOptionalString(workingDir); + + // Dispatch command creation to allow generator expressions in outputs. + this->AddGeneratorAction([=](cmLocalGenerator& lg, + const cmListFileBacktrace& lfbt) { + BacktraceGuard guard(this->Backtrace, lfbt); + detail::AddCustomCommandToTarget( + lg, lfbt, cmCommandOrigin::Project, t, byproducts, depends, commandLines, + type, GetCStrOrNull(commentStr), GetCStrOrNull(workingStr), + escapeOldStyle, uses_terminal, depfile, job_pool, command_expand_lists); + }); return t; } -void cmMakefile::CommitCustomCommandToTarget( - cmTarget* target, const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, cmCustomCommandType type, - const char* comment, const char* workingDir, bool escapeOldStyle, - bool uses_terminal, const std::string& depfile, const std::string& job_pool, - bool command_expand_lists) -{ - // Add the command to the appropriate build step for the target. - std::vector<std::string> no_output; - cmCustomCommand cc(this, no_output, byproducts, depends, commandLines, - comment, workingDir); - cc.SetEscapeOldStyle(escapeOldStyle); - cc.SetEscapeAllowMakeVars(true); - cc.SetUsesTerminal(uses_terminal); - cc.SetCommandExpandLists(command_expand_lists); - cc.SetDepfile(depfile); - cc.SetJobPool(job_pool); - switch (type) { - case cmCustomCommandType::PRE_BUILD: - target->AddPreBuildCommand(std::move(cc)); - break; - case cmCustomCommandType::PRE_LINK: - target->AddPreLinkCommand(std::move(cc)); - break; - case cmCustomCommandType::POST_BUILD: - target->AddPostBuildCommand(std::move(cc)); - break; - } - - this->AddTargetByproducts(target, byproducts); -} - -cmSourceFile* cmMakefile::AddCustomCommandToOutput( +void cmMakefile::AddCustomCommandToOutput( const std::string& output, const std::vector<std::string>& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, - const char* comment, const char* workingDir, bool replace, - bool escapeOldStyle, bool uses_terminal, bool command_expand_lists, - const std::string& depfile, const std::string& job_pool) + const char* comment, const char* workingDir, + const CommandSourceCallback& callback, bool replace, bool escapeOldStyle, + bool uses_terminal, bool command_expand_lists, const std::string& depfile, + const std::string& job_pool) { - std::vector<std::string> outputs; - outputs.push_back(output); std::vector<std::string> no_byproducts; cmImplicitDependsList no_implicit_depends; - return this->AddCustomCommandToOutput( - outputs, no_byproducts, depends, main_dependency, no_implicit_depends, - commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal, - command_expand_lists, depfile, job_pool); + this->AddCustomCommandToOutput( + { output }, no_byproducts, depends, main_dependency, no_implicit_depends, + commandLines, comment, workingDir, callback, replace, escapeOldStyle, + uses_terminal, command_expand_lists, depfile, job_pool); } -cmSourceFile* cmMakefile::AddCustomCommandToOutput( +void cmMakefile::AddCustomCommandToOutput( const std::vector<std::string>& outputs, const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const std::string& main_dependency, const cmImplicitDependsList& implicit_depends, const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, bool replace, bool escapeOldStyle, - bool uses_terminal, bool command_expand_lists, const std::string& depfile, - const std::string& job_pool) + const char* workingDir, const CommandSourceCallback& callback, bool replace, + bool escapeOldStyle, bool uses_terminal, bool command_expand_lists, + const std::string& depfile, const std::string& job_pool) { // Make sure there is at least one output. if (outputs.empty()) { cmSystemTools::Error("Attempt to add a custom rule with no output!"); - return nullptr; + return; } // Validate custom commands. if (!this->ValidateCustomCommand(commandLines)) { - return nullptr; + return; } // Always create the output sources and mark them generated. - this->CreateGeneratedSources(outputs); - this->CreateGeneratedSources(byproducts); - - return this->CommitCustomCommandToOutput( - outputs, byproducts, depends, main_dependency, implicit_depends, - commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal, - command_expand_lists, depfile, job_pool); -} - -cmSourceFile* cmMakefile::CommitCustomCommandToOutput( - const std::vector<std::string>& outputs, - const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, const std::string& main_dependency, - const cmImplicitDependsList& implicit_depends, - const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, bool replace, bool escapeOldStyle, - bool uses_terminal, bool command_expand_lists, const std::string& depfile, - const std::string& job_pool) -{ - // Choose a source file on which to store the custom command. - cmSourceFile* file = nullptr; - if (!commandLines.empty() && !main_dependency.empty()) { - // The main dependency was specified. Use it unless a different - // custom command already used it. - file = this->GetSource(main_dependency); - if (file && file->GetCustomCommand() && !replace) { - // The main dependency already has a custom command. - if (commandLines == file->GetCustomCommand()->GetCommandLines()) { - // The existing custom command is identical. Silently ignore - // the duplicate. - return file; - } - // The existing custom command is different. We need to - // generate a rule file for this new command. - file = nullptr; - } else if (!file) { - file = this->CreateSource(main_dependency); + this->CreateGeneratedOutputs(outputs); + this->CreateGeneratedByproducts(byproducts); + + // Strings could be moved into the callback function with C++14. + cm::optional<std::string> commentStr = MakeOptionalString(comment); + cm::optional<std::string> workingStr = MakeOptionalString(workingDir); + + // Dispatch command creation to allow generator expressions in outputs. + this->AddGeneratorAction([=](cmLocalGenerator& lg, + const cmListFileBacktrace& lfbt) { + BacktraceGuard guard(this->Backtrace, lfbt); + cmSourceFile* sf = detail::AddCustomCommandToOutput( + lg, lfbt, cmCommandOrigin::Project, outputs, byproducts, depends, + main_dependency, implicit_depends, commandLines, + GetCStrOrNull(commentStr), GetCStrOrNull(workingStr), replace, + escapeOldStyle, uses_terminal, command_expand_lists, depfile, job_pool); + if (callback && sf) { + callback(sf); } - } - - // Generate a rule file if the main dependency is not available. - if (!file) { - cmGlobalGenerator* gg = this->GetGlobalGenerator(); - - // Construct a rule file associated with the first output produced. - std::string outName = gg->GenerateRuleFile(outputs[0]); - - // Check if the rule file already exists. - file = this->GetSource(outName, cmSourceFileLocationKind::Known); - if (file && file->GetCustomCommand() && !replace) { - // The rule file already exists. - if (commandLines != file->GetCustomCommand()->GetCommandLines()) { - cmSystemTools::Error("Attempt to add a custom rule to output \"" + - outName + "\" which already has a custom rule."); - } - return file; - } - - // Create a cmSourceFile for the rule file. - if (!file) { - file = - this->CreateSource(outName, true, cmSourceFileLocationKind::Known); - } - file->SetProperty("__CMAKE_RULE", "1"); - } - - // Attach the custom command to the file. - if (file) { - // Construct a complete list of dependencies. - std::vector<std::string> depends2(depends); - if (!main_dependency.empty()) { - depends2.push_back(main_dependency); - } - - std::unique_ptr<cmCustomCommand> cc = cm::make_unique<cmCustomCommand>( - this, outputs, byproducts, depends2, commandLines, comment, workingDir); - cc->SetEscapeOldStyle(escapeOldStyle); - cc->SetEscapeAllowMakeVars(true); - cc->SetImplicitDepends(implicit_depends); - cc->SetUsesTerminal(uses_terminal); - cc->SetCommandExpandLists(command_expand_lists); - cc->SetDepfile(depfile); - cc->SetJobPool(job_pool); - file->SetCustomCommand(std::move(cc)); - - this->AddSourceOutputs(file, outputs, byproducts); - } - return file; + }); } void cmMakefile::AddCustomCommandOldStyle( @@ -1136,11 +1138,8 @@ void cmMakefile::AddCustomCommandOldStyle( if (sourceFiles.find(source)) { // The source looks like a real file. Use it as the main dependency. for (std::string const& output : outputs) { - cmSourceFile* sf = this->AddCustomCommandToOutput( - output, depends, source, commandLines, comment, nullptr); - if (sf) { - addRuleFileToTarget(sf); - } + this->AddCustomCommandToOutput(output, depends, source, commandLines, + comment, nullptr, addRuleFileToTarget); } } else { std::string no_main_dependency; @@ -1149,11 +1148,9 @@ void cmMakefile::AddCustomCommandOldStyle( // The source may not be a real file. Do not use a main dependency. for (std::string const& output : outputs) { - cmSourceFile* sf = this->AddCustomCommandToOutput( - output, depends2, no_main_dependency, commandLines, comment, nullptr); - if (sf) { - addRuleFileToTarget(sf); - } + this->AddCustomCommandToOutput(output, depends2, no_main_dependency, + commandLines, comment, nullptr, + addRuleFileToTarget); } } } @@ -1170,29 +1167,18 @@ bool cmMakefile::AppendCustomCommandToOutput( // Validate custom commands. if (this->ValidateCustomCommand(commandLines)) { - // Add command factory to allow generator expressions in output. - this->CommitAppendCustomCommandToOutput(output, depends, implicit_depends, - commandLines); + // Dispatch command creation to allow generator expressions in outputs. + this->AddGeneratorAction( + [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) { + BacktraceGuard guard(this->Backtrace, lfbt); + detail::AppendCustomCommandToOutput(lg, lfbt, output, depends, + implicit_depends, commandLines); + }); } return true; } -void cmMakefile::CommitAppendCustomCommandToOutput( - const std::string& output, const std::vector<std::string>& depends, - const cmImplicitDependsList& implicit_depends, - const cmCustomCommandLines& commandLines) -{ - // Lookup an existing command. - if (cmSourceFile* sf = this->GetSourceFileWithOutput(output)) { - if (cmCustomCommand* cc = sf->GetCustomCommand()) { - cc->AppendCommands(commandLines); - cc->AppendDepends(depends); - cc->AppendImplicitDepends(implicit_depends); - } - } -} - cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target) { std::string force = cmStrCat(this->GetCurrentBinaryDirectory(), @@ -1215,15 +1201,14 @@ cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target) } cmTarget* cmMakefile::AddUtilityCommand( - const std::string& utilityName, cmCommandOrigin origin, bool excludeFromAll, - const char* workingDirectory, const std::vector<std::string>& byproducts, + const std::string& utilityName, bool excludeFromAll, const char* workingDir, + const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle, const char* comment, bool uses_terminal, bool command_expand_lists, const std::string& job_pool) { - cmTarget* target = - this->AddNewUtilityTarget(utilityName, origin, excludeFromAll); + cmTarget* target = this->AddNewUtilityTarget(utilityName, excludeFromAll); // Validate custom commands. if ((commandLines.empty() && depends.empty()) || @@ -1236,45 +1221,26 @@ cmTarget* cmMakefile::AddUtilityCommand( this->GetOrCreateGeneratedSource(force.Name); // Always create the byproduct sources and mark them generated. - this->CreateGeneratedSources(byproducts); - - if (!comment) { - // Use an empty comment to avoid generation of default comment. - comment = ""; - } - - this->CommitUtilityCommand(target, force, workingDirectory, byproducts, - depends, commandLines, escapeOldStyle, comment, - uses_terminal, command_expand_lists, job_pool); + this->CreateGeneratedByproducts(byproducts); + + // Strings could be moved into the callback function with C++14. + cm::optional<std::string> commentStr = MakeOptionalString(comment); + cm::optional<std::string> workingStr = MakeOptionalString(workingDir); + + // Dispatch command creation to allow generator expressions in outputs. + this->AddGeneratorAction( + [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) { + BacktraceGuard guard(this->Backtrace, lfbt); + detail::AddUtilityCommand(lg, lfbt, cmCommandOrigin::Project, target, + force, GetCStrOrNull(workingStr), byproducts, + depends, commandLines, escapeOldStyle, + GetCStrOrNull(commentStr), uses_terminal, + command_expand_lists, job_pool); + }); return target; } -void cmMakefile::CommitUtilityCommand( - cmTarget* target, const cmUtilityOutput& force, const char* workingDirectory, - const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, bool escapeOldStyle, - const char* comment, bool uses_terminal, bool command_expand_lists, - const std::string& job_pool) -{ - std::vector<std::string> forced; - forced.push_back(force.Name); - std::string no_main_dependency; - cmImplicitDependsList no_implicit_depends; - bool no_replace = false; - cmSourceFile* sf = this->AddCustomCommandToOutput( - forced, byproducts, depends, no_main_dependency, no_implicit_depends, - commandLines, comment, workingDirectory, no_replace, escapeOldStyle, - uses_terminal, command_expand_lists, /*depfile=*/"", job_pool); - if (!force.NameCMP0049.empty()) { - target->AddSource(force.NameCMP0049); - } - if (sf) { - this->AddTargetByproducts(target, byproducts); - } -} - static void s_AddDefineFlag(std::string const& flag, std::string& dflags) { // remove any \n\r @@ -1342,28 +1308,27 @@ void cmMakefile::RemoveDefineFlag(std::string const& flag) void cmMakefile::AddCompileDefinition(std::string const& option) { - this->AppendProperty("COMPILE_DEFINITIONS", option.c_str()); + this->AppendProperty("COMPILE_DEFINITIONS", option); } void cmMakefile::AddCompileOption(std::string const& option) { - this->AppendProperty("COMPILE_OPTIONS", option.c_str()); + this->AppendProperty("COMPILE_OPTIONS", option); } void cmMakefile::AddLinkOption(std::string const& option) { - this->AppendProperty("LINK_OPTIONS", option.c_str()); + this->AppendProperty("LINK_OPTIONS", option); } void cmMakefile::AddLinkDirectory(std::string const& directory, bool before) { - cmListFileBacktrace lfbt = this->GetBacktrace(); if (before) { - this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(directory, - lfbt); + this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry( + directory, this->Backtrace); } else { - this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(directory, - lfbt); + this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry( + directory, this->Backtrace); } } @@ -1476,6 +1441,20 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent) this->RecursionDepth = parent->RecursionDepth; } +void cmMakefile::AddInstallGenerator(std::unique_ptr<cmInstallGenerator> g) +{ + if (g) { + this->InstallGenerators.push_back(std::move(g)); + } +} + +void cmMakefile::AddTestGenerator(std::unique_ptr<cmTestGenerator> g) +{ + if (g) { + this->TestGenerators.push_back(std::move(g)); + } +} + void cmMakefile::PushFunctionScope(std::string const& fileName, const cmPolicies::PolicyMap& pm) { @@ -1776,8 +1755,10 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath, cmSystemTools::MakeDirectory(binPath); - cmMakefile* subMf = new cmMakefile(this->GlobalGenerator, newSnapshot); - this->GetGlobalGenerator()->AddMakefile(subMf); + auto subMfu = + cm::make_unique<cmMakefile>(this->GlobalGenerator, newSnapshot); + auto subMf = subMfu.get(); + this->GetGlobalGenerator()->AddMakefile(std::move(subMfu)); if (excludeFromAll) { subMf->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); @@ -1789,8 +1770,8 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath, this->UnConfiguredDirectories.push_back(subMf); } - this->AddInstallGenerator(new cmInstallSubdirectoryGenerator( - subMf, binPath.c_str(), excludeFromAll)); + this->AddInstallGenerator(cm::make_unique<cmInstallSubdirectoryGenerator>( + subMf, binPath, excludeFromAll)); } const std::string& cmMakefile::GetCurrentSourceDirectory() const @@ -1820,20 +1801,19 @@ void cmMakefile::AddIncludeDirectories(const std::vector<std::string>& incs, return; } - cmListFileBacktrace lfbt = this->GetBacktrace(); std::string entryString = cmJoin(incs, ";"); if (before) { this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry( - entryString, lfbt); + entryString, this->Backtrace); } else { this->StateSnapshot.GetDirectory().AppendIncludeDirectoriesEntry( - entryString, lfbt); + entryString, this->Backtrace); } // Property on each target: for (auto& target : this->Targets) { cmTarget& t = target.second; - t.InsertInclude(entryString, lfbt, before); + t.InsertInclude(entryString, this->Backtrace, before); } } @@ -2027,7 +2007,7 @@ void cmMakefile::AddGlobalLinkInformation(cmTarget& target) target.AddLinkLibrary(*this, libraryName, libType); target.AppendProperty( "INTERFACE_LINK_LIBRARIES", - target.GetDebugGeneratorExpressions(libraryName, libType).c_str()); + target.GetDebugGeneratorExpressions(libraryName, libType)); } } } @@ -2080,7 +2060,8 @@ cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type, { auto it = this->Targets - .emplace(name, cmTarget(name, type, cmTarget::VisibilityNormal, this)) + .emplace(name, + cmTarget(name, type, cmTarget::VisibilityNormal, this, true)) .first; this->OrderedTargets.push_back(&it->second); this->GetGlobalGenerator()->IndexTarget(&it->second); @@ -2089,11 +2070,9 @@ cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type, } cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName, - cmCommandOrigin origin, bool excludeFromAll) { cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName); - target->SetIsGeneratorProvided(origin == cmCommandOrigin::Generator); if (excludeFromAll) { target->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); } @@ -2155,18 +2134,18 @@ cmSourceFile* cmMakefile::LinearGetSourceFileWithOutput( // Look through all the source files that have custom commands and see if the // custom command has the passed source file as an output. - for (cmSourceFile* src : this->SourceFiles) { + for (const auto& src : this->SourceFiles) { // Does this source file have a custom command? if (src->GetCustomCommand()) { // Does the output of the custom command match the source file name? if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) { // Return the first matching output. - return src; + return src.get(); } if (kind == cmSourceOutputKind::OutputOrByproduct) { if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) { // Do not return the source yet as there might be a matching output. - fallback = src; + fallback = src.get(); } } } @@ -2211,8 +2190,8 @@ cmSourceFile* cmMakefile::GetSourceFileWithOutput( (!o->second.Sources.SourceIsByproduct || kind == cmSourceOutputKind::OutputOrByproduct)) { // Source file could also be null pointer for example if we found the - // byproduct of a utility target or a PRE_BUILD, PRE_LINK, or POST_BUILD - // command of a target. + // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD + // command of a target, or a not yet created custom command. return o->second.Sources.Source; } return nullptr; @@ -2220,12 +2199,20 @@ cmSourceFile* cmMakefile::GetSourceFileWithOutput( bool cmMakefile::MightHaveCustomCommand(const std::string& name) const { - // This will have to be changed for delaying custom command creation, because - // GetSourceFileWithOutput requires the command to be already created. - if (cmSourceFile* sf = this->GetSourceFileWithOutput(name)) { - if (sf->GetCustomCommand()) { - return true; - } + if (this->DelayedOutputFilesHaveGenex || + cmGeneratorExpression::Find(name) != std::string::npos) { + // Could be more restrictive, but for now we assume that there could always + // be a match when generator expressions are involved. + return true; + } + // Also see LinearGetSourceFileWithOutput. + if (!cmSystemTools::FileIsFullPath(name)) { + return AnyOutputMatches(name, this->DelayedOutputFiles); + } + // Otherwise we use an efficient lookup map. + auto o = this->OutputToSource.find(name); + if (o != this->OutputToSource.end()) { + return o->second.SourceMightBeOutput; } return false; } @@ -2278,6 +2265,7 @@ void cmMakefile::UpdateOutputToSourceMap(std::string const& output, SourceEntry entry; entry.Sources.Source = source; entry.Sources.SourceIsByproduct = byproduct; + entry.SourceMightBeOutput = !byproduct; auto pr = this->OutputToSource.emplace(output, entry); if (!pr.second) { @@ -2287,6 +2275,7 @@ void cmMakefile::UpdateOutputToSourceMap(std::string const& output, (current.Sources.SourceIsByproduct && !byproduct)) { current.Sources.Source = source; current.Sources.SourceIsByproduct = false; + current.SourceMightBeOutput = true; } else { // Multiple custom commands produce the same output but may // be attached to a different source file (MAIN_DEPENDENCY). @@ -2478,7 +2467,7 @@ void cmMakefile::ExpandVariablesCMP0019() << " " << dirs << "\n"; /* clang-format on */ } - t.SetProperty("INCLUDE_DIRECTORIES", dirs.c_str()); + t.SetProperty("INCLUDE_DIRECTORIES", dirs); } } @@ -2739,7 +2728,7 @@ const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const std::vector<std::string> cmMakefile::GetDefinitions() const { std::vector<std::string> res = this->StateSnapshot.ClosureKeys(); - cmAppend(res, this->GetState()->GetCacheEntryKeys()); + cm::append(res, this->GetState()->GetCacheEntryKeys()); std::sort(res.begin(), res.end()); return res; } @@ -3514,24 +3503,25 @@ cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName, bool generated, cmSourceFileLocationKind kind) { - cmSourceFile* sf = new cmSourceFile(this, sourceName, kind); + auto sf = cm::make_unique<cmSourceFile>(this, sourceName, kind); if (generated) { sf->SetProperty("GENERATED", "1"); } - this->SourceFiles.push_back(sf); auto name = this->GetCMakeInstance()->StripExtension(sf->GetLocation().GetName()); #if defined(_WIN32) || defined(__APPLE__) name = cmSystemTools::LowerCase(name); #endif - this->SourceFileSearchIndex[name].push_back(sf); + this->SourceFileSearchIndex[name].push_back(sf.get()); // for "Known" paths add direct lookup (used for faster lookup in GetSource) if (kind == cmSourceFileLocationKind::Known) { - this->KnownFileSearchIndex[sourceName] = sf; + this->KnownFileSearchIndex[sourceName] = sf.get(); } - return sf; + this->SourceFiles.push_back(std::move(sf)); + + return this->SourceFiles.back().get(); } cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName, @@ -3553,11 +3543,41 @@ cmSourceFile* cmMakefile::GetOrCreateGeneratedSource( return sf; } -void cmMakefile::CreateGeneratedSources( +void cmMakefile::CreateGeneratedOutputs( const std::vector<std::string>& outputs) { - for (std::string const& output : outputs) { - this->GetOrCreateGeneratedSource(output); + for (std::string const& o : outputs) { + if (cmGeneratorExpression::Find(o) == std::string::npos) { + this->GetOrCreateGeneratedSource(o); + this->AddDelayedOutput(o); + } else { + this->DelayedOutputFilesHaveGenex = true; + } + } +} + +void cmMakefile::CreateGeneratedByproducts( + const std::vector<std::string>& byproducts) +{ + for (std::string const& o : byproducts) { + if (cmGeneratorExpression::Find(o) == std::string::npos) { + this->GetOrCreateGeneratedSource(o); + } + } +} + +void cmMakefile::AddDelayedOutput(std::string const& output) +{ + // Note that this vector might contain the output names in a different order + // than in source file iteration order. + this->DelayedOutputFiles.push_back(output); + + SourceEntry entry; + entry.SourceMightBeOutput = true; + + auto pr = this->OutputToSource.emplace(output, entry); + if (!pr.second) { + pr.first->second.SourceMightBeOutput = true; } } @@ -3630,8 +3650,7 @@ int cmMakefile::TryCompile(const std::string& srcdir, // be run that way but the cmake object requires a vailid path cmake cm(cmake::RoleProject, cmState::Project); cm.SetIsInTryCompile(true); - cmGlobalGenerator* gg = - cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName()); + auto gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName()); if (!gg) { this->IssueMessage(MessageType::INTERNAL_ERROR, "Global generator '" + @@ -3642,7 +3661,7 @@ int cmMakefile::TryCompile(const std::string& srcdir, return 1; } gg->RecursionDepth = this->RecursionDepth; - cm.SetGlobalGenerator(gg); + cm.SetGlobalGenerator(std::move(gg)); // do a configure cm.SetHomeDirectory(srcdir); @@ -3651,7 +3670,7 @@ int cmMakefile::TryCompile(const std::string& srcdir, cm.SetGeneratorPlatform(this->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM")); cm.SetGeneratorToolset(this->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET")); cm.LoadCache(); - if (!gg->IsMultiConfig()) { + if (!cm.GetGlobalGenerator()->IsMultiConfig()) { if (const char* config = this->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION")) { // Tell the single-configuration generator which one to use. @@ -3697,7 +3716,8 @@ int cmMakefile::TryCompile(const std::string& srcdir, cm.SetCacheArgs(*cmakeArgs); } // to save time we pass the EnableLanguage info directly - gg->EnableLanguagesFromGenerator(this->GetGlobalGenerator(), this); + cm.GetGlobalGenerator()->EnableLanguagesFromGenerator( + this->GetGlobalGenerator(), this); if (this->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) { cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "TRUE", "", cmStateEnums::INTERNAL); @@ -3777,7 +3797,8 @@ void cmMakefile::DisplayStatus(const std::string& message, float s) const } std::string cmMakefile::GetModulesFile(const std::string& filename, - bool& system) const + bool& system, bool debug, + std::string& debugBuffer) const { std::string result; @@ -3808,6 +3829,9 @@ std::string cmMakefile::GetModulesFile(const std::string& filename, moduleInCMakeModulePath = itempl; break; } + if (debug) { + debugBuffer = cmStrCat(debugBuffer, " ", itempl, "\n"); + } } } @@ -3816,6 +3840,9 @@ std::string cmMakefile::GetModulesFile(const std::string& filename, cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/", filename); cmSystemTools::ConvertToUnixSlashes(moduleInCMakeRoot); if (!cmSystemTools::FileExists(moduleInCMakeRoot)) { + if (debug) { + debugBuffer = cmStrCat(debugBuffer, " ", moduleInCMakeRoot, "\n"); + } moduleInCMakeRoot.clear(); } @@ -4029,16 +4056,14 @@ int cmMakefile::ConfigureFile(const std::string& infile, void cmMakefile::SetProperty(const std::string& prop, const char* value) { - cmListFileBacktrace lfbt = this->GetBacktrace(); - this->StateSnapshot.GetDirectory().SetProperty(prop, value, lfbt); + this->StateSnapshot.GetDirectory().SetProperty(prop, value, this->Backtrace); } -void cmMakefile::AppendProperty(const std::string& prop, const char* value, - bool asString) +void cmMakefile::AppendProperty(const std::string& prop, + const std::string& value, bool asString) { - cmListFileBacktrace lfbt = this->GetBacktrace(); this->StateSnapshot.GetDirectory().AppendProperty(prop, value, asString, - lfbt); + this->Backtrace); } const char* cmMakefile::GetProperty(const std::string& prop) const @@ -4090,9 +4115,10 @@ cmTest* cmMakefile::CreateTest(const std::string& testName) if (test) { return test; } - test = new cmTest(this); - test->SetName(testName); - this->Tests[testName] = test; + auto newTest = cm::make_unique<cmTest>(this); + test = newTest.get(); + newTest->SetName(testName); + this->Tests[testName] = std::move(newTest); return test; } @@ -4100,7 +4126,7 @@ cmTest* cmMakefile::GetTest(const std::string& testName) const { auto mi = this->Tests.find(testName); if (mi != this->Tests.end()) { - return mi->second; + return mi->second.get(); } return nullptr; } @@ -4108,7 +4134,7 @@ cmTest* cmMakefile::GetTest(const std::string& testName) const void cmMakefile::GetTests(const std::string& config, std::vector<cmTest*>& tests) { - for (auto generator : this->GetTestGenerators()) { + for (const auto& generator : this->GetTestGenerators()) { if (generator->TestsForConfig(config)) { tests.push_back(generator->GetTest()); } @@ -4214,15 +4240,15 @@ cmTarget* cmMakefile::AddImportedTarget(const std::string& name, new cmTarget(name, type, global ? cmTarget::VisibilityImportedGlobally : cmTarget::VisibilityImported, - this)); + this, true)); // Add to the set of available imported targets. this->ImportedTargets[name] = target.get(); this->GetGlobalGenerator()->IndexTarget(target.get()); // Transfer ownership to this cmMakefile object. - this->ImportedTargetsOwned.push_back(target.get()); - return target.release(); + this->ImportedTargetsOwned.push_back(std::move(target)); + return this->ImportedTargetsOwned.back().get(); } cmTarget* cmMakefile::FindTargetToUse(const std::string& name, @@ -4487,7 +4513,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, // Deprecate old policies, especially those that require a lot // of code to maintain the old behavior. - if (status == cmPolicies::OLD && id <= cmPolicies::CMP0067 && + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0071 && !(this->GetCMakeInstance()->GetIsInTryCompile() && ( // Policies set by cmCoreTryCompile::TryCompileCode. @@ -4587,17 +4613,21 @@ static const char* const C_FEATURES[] = { nullptr FOR_EACH_C_FEATURE( static const char* const CXX_FEATURES[] = { nullptr FOR_EACH_CXX_FEATURE( FEATURE_STRING) }; + +static const char* const CUDA_FEATURES[] = { nullptr FOR_EACH_CUDA_FEATURE( + FEATURE_STRING) }; #undef FEATURE_STRING static const char* const C_STANDARDS[] = { "90", "99", "11" }; static const char* const CXX_STANDARDS[] = { "98", "11", "14", "17", "20" }; +static const char* const CUDA_STANDARDS[] = { "03", "11", "14", "17", "20" }; bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, const std::string& feature, std::string* error) const { if (cmGeneratorExpression::Find(feature) != std::string::npos) { - target->AppendProperty("COMPILE_FEATURES", feature.c_str()); + target->AppendProperty("COMPILE_FEATURES", feature); return true; } @@ -4628,11 +4658,15 @@ bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, return false; } - target->AppendProperty("COMPILE_FEATURES", feature.c_str()); + target->AppendProperty("COMPILE_FEATURES", feature); - return lang == "C" || lang == "OBJC" - ? this->AddRequiredTargetCFeature(target, feature, lang, error) - : this->AddRequiredTargetCxxFeature(target, feature, lang, error); + if (lang == "C" || lang == "OBJC") { + return this->AddRequiredTargetCFeature(target, feature, lang, error); + } + if (lang == "CUDA") { + return this->AddRequiredTargetCudaFeature(target, feature, lang, error); + } + return this->AddRequiredTargetCxxFeature(target, feature, lang, error); } bool cmMakefile::CompileFeatureKnown(cmTarget const* target, @@ -4656,6 +4690,13 @@ bool cmMakefile::CompileFeatureKnown(cmTarget const* target, lang = "CXX"; return true; } + bool isCudaFeature = + std::find_if(cm::cbegin(CUDA_FEATURES) + 1, cm::cend(CUDA_FEATURES), + cmStrCmp(feature)) != cm::cend(CUDA_FEATURES); + if (isCudaFeature) { + lang = "CUDA"; + return true; + } std::ostringstream e; if (error) { e << "specified"; @@ -4724,9 +4765,13 @@ bool cmMakefile::HaveStandardAvailable(cmTarget const* target, std::string const& lang, const std::string& feature) const { - return lang == "C" || lang == "OBJC" - ? this->HaveCStandardAvailable(target, feature, lang) - : this->HaveCxxStandardAvailable(target, feature, lang); + if (lang == "C" || lang == "OBJC") { + return this->HaveCStandardAvailable(target, feature, lang); + } + if (lang == "CUDA") { + return this->HaveCudaStandardAvailable(target, feature, lang); + } + return this->HaveCxxStandardAvailable(target, feature, lang); } bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, @@ -4809,6 +4854,14 @@ bool cmMakefile::IsLaterStandard(std::string const& lang, return std::find_if(rhsIt, cm::cend(C_STANDARDS), cmStrCmp(lhs)) != cm::cend(C_STANDARDS); } + if (lang == "CUDA") { + const char* const* rhsIt = std::find_if( + cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), cmStrCmp(rhs)); + + return std::find_if(rhsIt, cm::cend(CUDA_STANDARDS), cmStrCmp(lhs)) != + cm::cend(CUDA_STANDARDS); + } + const char* const* rhsIt = std::find_if( cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(rhs)); @@ -4953,27 +5006,6 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, } } - const char* existingCudaStandard = target->GetProperty("CUDA_STANDARD"); - const char* const* existingCudaLevel = nullptr; - if (existingCudaStandard) { - existingCudaLevel = - std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), - cmStrCmp(existingCudaStandard)); - if (existingCudaLevel == cm::cend(CXX_STANDARDS)) { - std::ostringstream e; - e << "The CUDA_STANDARD property on target \"" << target->GetName() - << "\" contained an invalid value: \"" << existingCudaStandard - << "\"."; - if (error) { - *error = e.str(); - } else { - this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, - e.str(), this->Backtrace); - } - return false; - } - } - /* clang-format off */ const char* const* needCxxLevel = needCxx20 ? &CXX_STANDARDS[4] @@ -4990,11 +5022,164 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, if (!existingCxxLevel || existingCxxLevel < needCxxLevel) { target->SetProperty(cmStrCat(lang, "_STANDARD"), *needCxxLevel); } + } + + return true; +} + +bool cmMakefile::HaveCudaStandardAvailable(cmTarget const* target, + const std::string& feature, + std::string const& lang) const +{ + const char* defaultCudaStandard = + this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); + if (!defaultCudaStandard) { + this->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("CMAKE_", lang, + "_STANDARD_DEFAULT is not set. COMPILE_FEATURES support " + "not fully configured for this compiler.")); + // Return true so the caller does not try to lookup the default standard. + return true; + } + if (std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), + cmStrCmp(defaultCudaStandard)) == + cm::cend(CUDA_STANDARDS)) { + const std::string e = + cmStrCat("The CMAKE_", lang, "_STANDARD_DEFAULT variable contains an ", + "invalid value: \"", defaultCudaStandard, "\"."); + this->IssueMessage(MessageType::INTERNAL_ERROR, e); + return false; + } + + bool needCuda03 = false; + bool needCuda11 = false; + bool needCuda14 = false; + bool needCuda17 = false; + bool needCuda20 = false; + this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11, + needCuda14, needCuda17, needCuda20); + + const char* existingCudaStandard = + target->GetProperty(cmStrCat(lang, "_STANDARD")); + if (!existingCudaStandard) { + existingCudaStandard = defaultCudaStandard; + } + + const char* const* existingCudaLevel = + std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), + cmStrCmp(existingCudaStandard)); + if (existingCudaLevel == cm::cend(CUDA_STANDARDS)) { + const std::string e = cmStrCat( + "The ", lang, "_STANDARD property on target \"", target->GetName(), + "\" contained an invalid value: \"", existingCudaStandard, "\"."); + this->IssueMessage(MessageType::FATAL_ERROR, e); + return false; + } + + /* clang-format off */ + const char* const* needCudaLevel = + needCuda20 ? &CUDA_STANDARDS[4] + : needCuda17 ? &CUDA_STANDARDS[3] + : needCuda14 ? &CUDA_STANDARDS[2] + : needCuda11 ? &CUDA_STANDARDS[1] + : needCuda03 ? &CUDA_STANDARDS[0] + : nullptr; + /* clang-format on */ + + return !needCudaLevel || needCudaLevel <= existingCudaLevel; +} + +void cmMakefile::CheckNeededCudaLanguage(const std::string& feature, + std::string const& lang, + bool& needCuda03, bool& needCuda11, + bool& needCuda14, bool& needCuda17, + bool& needCuda20) const +{ + if (const char* propCuda03 = + this->GetDefinition(cmStrCat("CMAKE_", lang, "03_COMPILE_FEATURES"))) { + std::vector<std::string> props = cmExpandedList(propCuda03); + needCuda03 = cmContains(props, feature); + } + if (const char* propCuda11 = + this->GetDefinition(cmStrCat("CMAKE_", lang, "11_COMPILE_FEATURES"))) { + std::vector<std::string> props = cmExpandedList(propCuda11); + needCuda11 = cmContains(props, feature); + } + if (const char* propCuda14 = + this->GetDefinition(cmStrCat("CMAKE_", lang, "14_COMPILE_FEATURES"))) { + std::vector<std::string> props = cmExpandedList(propCuda14); + needCuda14 = cmContains(props, feature); + } + if (const char* propCuda17 = + this->GetDefinition(cmStrCat("CMAKE_", lang, "17_COMPILE_FEATURES"))) { + std::vector<std::string> props = cmExpandedList(propCuda17); + needCuda17 = cmContains(props, feature); + } + if (const char* propCuda20 = + this->GetDefinition(cmStrCat("CMAKE_", lang, "20_COMPILE_FEATURES"))) { + std::vector<std::string> props = cmExpandedList(propCuda20); + needCuda20 = cmContains(props, feature); + } +} + +bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, + const std::string& feature, + std::string const& lang, + std::string* error) const +{ + bool needCuda03 = false; + bool needCuda11 = false; + bool needCuda14 = false; + bool needCuda17 = false; + bool needCuda20 = false; + + this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11, + needCuda14, needCuda17, needCuda20); + + const char* existingCudaStandard = + target->GetProperty(cmStrCat(lang, "_STANDARD")); + if (existingCudaStandard == nullptr) { + const char* defaultCudaStandard = + this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); + if (defaultCudaStandard && *defaultCudaStandard) { + existingCudaStandard = defaultCudaStandard; + } + } + const char* const* existingCudaLevel = nullptr; + if (existingCudaStandard) { + existingCudaLevel = + std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), + cmStrCmp(existingCudaStandard)); + if (existingCudaLevel == cm::cend(CUDA_STANDARDS)) { + const std::string e = cmStrCat( + "The ", lang, "_STANDARD property on target \"", target->GetName(), + "\" contained an invalid value: \"", existingCudaStandard, "\"."); + if (error) { + *error = e; + } else { + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, + this->Backtrace); + } + return false; + } + } + + /* clang-format off */ + const char* const* needCudaLevel = + needCuda20 ? &CUDA_STANDARDS[4] + : needCuda17 ? &CUDA_STANDARDS[3] + : needCuda14 ? &CUDA_STANDARDS[2] + : needCuda11 ? &CUDA_STANDARDS[1] + : needCuda03 ? &CUDA_STANDARDS[0] + : nullptr; + /* clang-format on */ + if (needCudaLevel) { // Ensure the CUDA language level is high enough to support - // the needed C++ features. - if (!existingCudaLevel || existingCudaLevel < needCxxLevel) { - target->SetProperty("CUDA_STANDARD", *needCxxLevel); + // the needed CUDA features. + if (!existingCudaLevel || existingCudaLevel < needCudaLevel) { + target->SetProperty("CUDA_STANDARD", *needCudaLevel); } } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 6e59494..081e69d 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -49,6 +49,7 @@ class cmGeneratorExpressionEvaluationFile; class cmGlobalGenerator; class cmImplicitDependsList; class cmInstallGenerator; +class cmLocalGenerator; class cmMessenger; class cmSourceFile; class cmState; @@ -116,6 +117,9 @@ public: bool ReadListFile(const std::string& filename); + bool ReadListFileAsString(const std::string& content, + const std::string& virtualFileName); + bool ReadDependentFile(const std::string& filename, bool noPolicyScope = true); @@ -134,7 +138,7 @@ public: std::unique_ptr<cmFunctionBlocker> RemoveFunctionBlocker(); /** - * Try running cmake and building a file. This is used for dynalically + * Try running cmake and building a file. This is used for dynamically * loaded commands, not as part of the usual build process. */ int TryCompile(const std::string& srcdir, const std::string& bindir, @@ -151,54 +155,64 @@ public: bool EnforceUniqueName(std::string const& name, std::string& msg, bool isCustom = false) const; - using FinalAction = std::function<void(cmMakefile&)>; + using GeneratorAction = + std::function<void(cmLocalGenerator&, const cmListFileBacktrace&)>; /** - * Register an action that is executed during FinalPass + * Register an action that is executed during Generate */ - void AddFinalAction(FinalAction action); + void AddGeneratorAction(GeneratorAction action); /** - * Perform FinalPass, Library dependency analysis etc before output of the - * makefile. + * Perform generate actions, Library dependency analysis etc before output of + * the makefile. */ - void ConfigureFinalPass(); + void Generate(cmLocalGenerator& lg); /** - * run all FinalActions. + * Get the target for PRE_BUILD, PRE_LINK, or POST_BUILD commands. */ - void FinalPass(); + cmTarget* GetCustomCommandTarget(const std::string& target, + cmObjectLibraryCommands objLibCommands, + const cmListFileBacktrace& lfbt) const; /** - * Get the target for PRE_BUILD, PRE_LINK, or POST_BUILD commands. + * Dispatch adding a custom PRE_BUILD, PRE_LINK, or POST_BUILD command to a + * target. */ - cmTarget* GetCustomCommandTarget( - const std::string& target, cmObjectLibraryCommands objLibCommands) const; - - /** Add a custom command to the build. */ cmTarget* AddCustomCommandToTarget( const std::string& target, const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, cmCustomCommandType type, const char* comment, const char* workingDir, bool escapeOldStyle = true, bool uses_terminal = false, const std::string& depfile = "", - const std::string& job_pool = "", bool command_expand_lists = false, - cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject); - cmSourceFile* AddCustomCommandToOutput( + const std::string& job_pool = "", bool command_expand_lists = false); + + /** + * Called for each file with custom command. + */ + using CommandSourceCallback = std::function<void(cmSourceFile*)>; + + /** + * Dispatch adding a custom command to a source file. + */ + void AddCustomCommandToOutput( const std::string& output, const std::vector<std::string>& depends, const std::string& main_dependency, const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, bool replace = false, bool escapeOldStyle = true, + const char* workingDir, const CommandSourceCallback& callback = nullptr, + bool replace = false, bool escapeOldStyle = true, bool uses_terminal = false, bool command_expand_lists = false, const std::string& depfile = "", const std::string& job_pool = ""); - cmSourceFile* AddCustomCommandToOutput( + void AddCustomCommandToOutput( const std::vector<std::string>& outputs, const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const std::string& main_dependency, const cmImplicitDependsList& implicit_depends, const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, bool replace = false, bool escapeOldStyle = true, + const char* workingDir, const CommandSourceCallback& callback = nullptr, + bool replace = false, bool escapeOldStyle = true, bool uses_terminal = false, bool command_expand_lists = false, const std::string& depfile = "", const std::string& job_pool = ""); void AddCustomCommandOldStyle(const std::string& target, @@ -244,7 +258,7 @@ public: /** Create a target instance for the utility. */ cmTarget* AddNewUtilityTarget(const std::string& utilityName, - cmCommandOrigin origin, bool excludeFromAll); + bool excludeFromAll); /** * Add an executable to the build. @@ -259,13 +273,12 @@ public: cmUtilityOutput GetUtilityOutput(cmTarget* target); /** - * Add a utility to the build. A utility target is a command that - * is run every time the target is built. + * Dispatch adding a utility to the build. A utility target is a command + * that is run every time the target is built. */ cmTarget* AddUtilityCommand( - const std::string& utilityName, cmCommandOrigin origin, - bool excludeFromAll, const char* workingDirectory, - const std::vector<std::string>& byproducts, + const std::string& utilityName, bool excludeFromAll, + const char* workingDir, const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle = true, const char* comment = nullptr, bool uses_terminal = false, @@ -304,6 +317,12 @@ public: void AddCacheDefinition(const std::string& name, const char* value, const char* doc, cmStateEnums::CacheEntryType type, bool force = false); + void AddCacheDefinition(const std::string& name, const std::string& value, + const char* doc, cmStateEnums::CacheEntryType type, + bool force = false) + { + AddCacheDefinition(name, value.c_str(), doc, type, force); + } /** * Remove a variable definition from the build. This is not valid @@ -409,9 +428,9 @@ public: { this->ComplainFileRegularExpression = regex; } - const char* GetComplainRegularExpression() const + const std::string& GetComplainRegularExpression() const { - return this->ComplainFileRegularExpression.c_str(); + return this->ComplainFileRegularExpression; } // -- List of targets @@ -421,7 +440,7 @@ public: /** Get the target map - const version */ cmTargetMap const& GetTargets() const { return this->Targets; } - const std::vector<cmTarget*>& GetOwnedImportedTargets() const + const std::vector<std::unique_ptr<cmTarget>>& GetOwnedImportedTargets() const { return this->ImportedTargetsOwned; } @@ -717,7 +736,7 @@ public: /** * Get all the source files this makefile knows about */ - const std::vector<cmSourceFile*>& GetSourceFiles() const + const std::vector<std::unique_ptr<cmSourceFile>>& GetSourceFiles() const { return this->SourceFiles; } @@ -756,14 +775,25 @@ public: std::string GetModulesFile(const std::string& name) const { bool system; - return this->GetModulesFile(name, system); + std::string debugBuffer; + return this->GetModulesFile(name, system, false, debugBuffer); + } + + /** + * Return a location of a file in cmake or custom modules directory + */ + std::string GetModulesFile(const std::string& name, bool& system) const + { + std::string debugBuffer; + return this->GetModulesFile(name, system, false, debugBuffer); } - std::string GetModulesFile(const std::string& name, bool& system) const; + std::string GetModulesFile(const std::string& name, bool& system, bool debug, + std::string& debugBuffer) const; //! Set/Get a property of this directory void SetProperty(const std::string& prop, const char* value); - void AppendProperty(const std::string& prop, const char* value, + void AppendProperty(const std::string& prop, const std::string& value, bool asString = false); const char* GetProperty(const std::string& prop) const; const char* GetProperty(const std::string& prop, bool chain) const; @@ -773,28 +803,22 @@ public: //! Initialize a makefile from its parent void InitializeFromParent(cmMakefile* parent); - void AddInstallGenerator(cmInstallGenerator* g) - { - if (g) { - this->InstallGenerators.push_back(g); - } - } - std::vector<cmInstallGenerator*>& GetInstallGenerators() + void AddInstallGenerator(std::unique_ptr<cmInstallGenerator> g); + + std::vector<std::unique_ptr<cmInstallGenerator>>& GetInstallGenerators() { return this->InstallGenerators; } - const std::vector<cmInstallGenerator*>& GetInstallGenerators() const + const std::vector<std::unique_ptr<cmInstallGenerator>>& + GetInstallGenerators() const { return this->InstallGenerators; } - void AddTestGenerator(cmTestGenerator* g) - { - if (g) { - this->TestGenerators.push_back(g); - } - } - const std::vector<cmTestGenerator*>& GetTestGenerators() const + void AddTestGenerator(std::unique_ptr<cmTestGenerator> g); + + const std::vector<std::unique_ptr<cmTestGenerator>>& GetTestGenerators() + const { return this->TestGenerators; } @@ -927,7 +951,8 @@ public: std::unique_ptr<cmCompiledGeneratorExpression> outputName, std::unique_ptr<cmCompiledGeneratorExpression> condition, bool inputIsContent); - std::vector<cmGeneratorExpressionEvaluationFile*> GetEvaluationFiles() const; + const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>& + GetEvaluationFiles() const; std::vector<cmExportBuildFileGenerator*> GetExportBuildFileGenerators() const; @@ -962,8 +987,7 @@ protected: using TargetsVec = std::vector<cmTarget*>; TargetsVec OrderedTargets; - using SourceFileVec = std::vector<cmSourceFile*>; - SourceFileVec SourceFiles; + std::vector<std::unique_ptr<cmSourceFile>> SourceFiles; // Because cmSourceFile names are compared in a fuzzy way (see // cmSourceFileLocation::Match()) we can't have a straight mapping from @@ -971,14 +995,15 @@ protected: // Name portion of the cmSourceFileLocation and then compare on the list of // cmSourceFiles that might match that name. Note that on platforms which // have a case-insensitive filesystem we store the key in all lowercase. - using SourceFileMap = std::unordered_map<std::string, SourceFileVec>; + using SourceFileMap = + std::unordered_map<std::string, std::vector<cmSourceFile*>>; SourceFileMap SourceFileSearchIndex; // For "Known" paths we can store a direct filename to cmSourceFile map std::unordered_map<std::string, cmSourceFile*> KnownFileSearchIndex; // Tests - std::map<std::string, cmTest*> Tests; + std::map<std::string, std::unique_ptr<cmTest>> Tests; // The set of include directories that are marked as system include // directories. @@ -987,8 +1012,8 @@ protected: std::vector<std::string> ListFiles; std::vector<std::string> OutputFiles; - std::vector<cmInstallGenerator*> InstallGenerators; - std::vector<cmTestGenerator*> TestGenerators; + std::vector<std::unique_ptr<cmInstallGenerator>> InstallGenerators; + std::vector<std::unique_ptr<cmTestGenerator>> TestGenerators; std::string ComplainFileRegularExpression; std::string DefineFlags; @@ -1001,7 +1026,6 @@ protected: size_t ObjectLibrariesSourceGroupIndex; #endif - std::vector<FinalAction> FinalActions; cmGlobalGenerator* GlobalGenerator; bool IsFunctionBlocked(const cmListFileFunction& lff, cmExecutionStatus& status); @@ -1011,6 +1035,8 @@ private: cmListFileBacktrace Backtrace; int RecursionDepth; + void DoGenerate(cmLocalGenerator& lg); + void ReadListFile(cmListFile const& listFile, const std::string& filenametoread); @@ -1038,13 +1064,14 @@ private: std::vector<cmMakefile*> UnConfiguredDirectories; std::vector<cmExportBuildFileGenerator*> ExportBuildFileGenerators; - std::vector<cmGeneratorExpressionEvaluationFile*> EvaluationFiles; + std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>> + EvaluationFiles; std::vector<cmExecutionStatus*> ExecutionStatusStack; friend class cmMakefileCall; friend class cmParseFileScope; - std::vector<cmTarget*> ImportedTargetsOwned; + std::vector<std::unique_ptr<cmTarget>> ImportedTargetsOwned; using TargetMap = std::unordered_map<std::string, cmTarget*>; TargetMap ImportedTargets; @@ -1080,38 +1107,15 @@ private: bool ValidateCustomCommand(const cmCustomCommandLines& commandLines) const; - void CreateGeneratedSources(const std::vector<std::string>& outputs); + void CreateGeneratedOutputs(const std::vector<std::string>& outputs); + void CreateGeneratedByproducts(const std::vector<std::string>& byproducts); - void CommitCustomCommandToTarget( - cmTarget* target, const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, cmCustomCommandType type, - const char* comment, const char* workingDir, bool escapeOldStyle, - bool uses_terminal, const std::string& depfile, - const std::string& job_pool, bool command_expand_lists); - cmSourceFile* CommitCustomCommandToOutput( - const std::vector<std::string>& outputs, - const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const std::string& main_dependency, - const cmImplicitDependsList& implicit_depends, - const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, bool replace, bool escapeOldStyle, - bool uses_terminal, bool command_expand_lists, const std::string& depfile, - const std::string& job_pool); - void CommitAppendCustomCommandToOutput( - const std::string& output, const std::vector<std::string>& depends, - const cmImplicitDependsList& implicit_depends, - const cmCustomCommandLines& commandLines); + std::vector<BT<GeneratorAction>> GeneratorActions; + bool GeneratorActionsInvoked = false; + bool DelayedOutputFilesHaveGenex = false; + std::vector<std::string> DelayedOutputFiles; - void CommitUtilityCommand(cmTarget* target, const cmUtilityOutput& force, - const char* workingDirectory, - const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, - bool escapeOldStyle, const char* comment, - bool uses_terminal, bool command_expand_lists, - const std::string& job_pool); + void AddDelayedOutput(std::string const& output); /** * See LinearGetSourceFileWithOutput for background information @@ -1131,6 +1135,7 @@ private: struct SourceEntry { cmSourcesWithOutput Sources; + bool SourceMightBeOutput = false; }; // A map for fast output to input look up. @@ -1149,11 +1154,14 @@ private: bool AddRequiredTargetCFeature(cmTarget* target, const std::string& feature, std::string const& lang, std::string* error = nullptr) const; - bool AddRequiredTargetCxxFeature(cmTarget* target, const std::string& feature, std::string const& lang, std::string* error = nullptr) const; + bool AddRequiredTargetCudaFeature(cmTarget* target, + const std::string& feature, + std::string const& lang, + std::string* error = nullptr) const; void CheckNeededCLanguage(const std::string& feature, std::string const& lang, bool& needC90, @@ -1162,6 +1170,10 @@ private: std::string const& lang, bool& needCxx98, bool& needCxx11, bool& needCxx14, bool& needCxx17, bool& needCxx20) const; + void CheckNeededCudaLanguage(const std::string& feature, + std::string const& lang, bool& needCuda03, + bool& needCuda11, bool& needCuda14, + bool& needCuda17, bool& needCuda20) const; bool HaveCStandardAvailable(cmTarget const* target, const std::string& feature, @@ -1169,6 +1181,9 @@ private: bool HaveCxxStandardAvailable(cmTarget const* target, const std::string& feature, std::string const& lang) const; + bool HaveCudaStandardAvailable(cmTarget const* target, + const std::string& feature, + std::string const& lang) const; void CheckForUnusedVariables() const; diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 40265ff..0471a45 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -9,8 +9,8 @@ #include <vector> #include <cm/memory> +#include <cmext/algorithm> -#include "cmAlgorithms.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" @@ -35,10 +35,9 @@ cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator( { this->CustomCommandDriver = OnDepends; this->TargetNames = - this->GeneratorTarget->GetExecutableNames(this->ConfigName); + this->GeneratorTarget->GetExecutableNames(this->GetConfigName()); - this->OSXBundleGenerator = - cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName); + this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); } @@ -64,7 +63,7 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles() // write the link rules this->WriteExecutableRule(false); - if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) { + if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->GetConfigName())) { // Write rules to link an installable version of the target. this->WriteExecutableRule(true); } @@ -85,7 +84,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( { #ifndef CMAKE_BOOTSTRAP const bool requiresDeviceLinking = requireDeviceLinking( - *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName); + *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName()); if (!requiresDeviceLinking) { return; } @@ -141,10 +140,10 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( // Add language feature flags. this->LocalGenerator->AddLanguageFlagsForLinking( - flags, this->GeneratorTarget, linkLanguage, this->ConfigName); + flags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); - this->LocalGenerator->AddArchitectureFlags(flags, this->GeneratorTarget, - linkLanguage, this->ConfigName); + this->LocalGenerator->AddArchitectureFlags( + flags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); // Add target-specific linker flags. this->GetTargetLinkFlags(linkFlags, linkLanguage); @@ -197,6 +196,8 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects, buildObjs, depends, useWatcomQuote); + std::string const& aixExports = this->GetAIXExports(this->GetConfigName()); + cmRulePlaceholderExpander::RuleVariables vars; std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); @@ -213,12 +214,14 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal), output); - std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB(); + std::string targetFullPathCompilePDB = + this->ComputeTargetCompilePDB(this->GetConfigName()); std::string targetOutPathCompilePDB = this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB, cmOutputConverter::SHELL); vars.Language = linkLanguage.c_str(); + vars.AIXExports = aixExports.c_str(); vars.Objects = buildObjs.c_str(); vars.ObjectDir = objectDir.c_str(); vars.Target = target.c_str(); @@ -263,7 +266,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); - cmAppend(commands, commands1); + cm::append(commands, commands1); commands1.clear(); // Write the build rule. @@ -287,12 +290,14 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Get the name of the executable to generate. cmGeneratorTarget::Names targetNames = - this->GeneratorTarget->GetExecutableNames(this->ConfigName); + this->GeneratorTarget->GetExecutableNames(this->GetConfigName()); // Construct the full path version of the names. - std::string outpath = this->GeneratorTarget->GetDirectory(this->ConfigName); + std::string outpath = + this->GeneratorTarget->GetDirectory(this->GetConfigName()); if (this->GeneratorTarget->IsAppBundleOnApple()) { - this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath); + this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath, + this->GetConfigName()); } outpath += '/'; std::string outpathImp; @@ -308,18 +313,18 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) cmSystemTools::MakeDirectory(outpath); if (!targetNames.ImportLibrary.empty()) { outpathImp = this->GeneratorTarget->GetDirectory( - this->ConfigName, cmStateEnums::ImportLibraryArtifact); + this->GetConfigName(), cmStateEnums::ImportLibraryArtifact); cmSystemTools::MakeDirectory(outpathImp); outpathImp += '/'; } } std::string compilePdbOutputPath = - this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName); + this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName()); cmSystemTools::MakeDirectory(compilePdbOutputPath); std::string pdbOutputPath = - this->GeneratorTarget->GetPDBDirectory(this->ConfigName); + this->GeneratorTarget->GetPDBDirectory(this->GetConfigName()); cmSystemTools::MakeDirectory(pdbOutputPath); pdbOutputPath += '/'; @@ -347,7 +352,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Get the language to use for linking this executable. std::string linkLanguage = - this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); // Make sure we have a link language. if (linkLanguage.empty()) { @@ -380,7 +385,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Add flags to create an executable. this->LocalGenerator->AddConfigVariableFlags( - linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->ConfigName); + linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->GetConfigName()); if (this->GeneratorTarget->GetPropertyAsBool("WIN32_EXECUTABLE")) { this->LocalGenerator->AppendFlags( @@ -409,25 +414,26 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Add language feature flags. this->LocalGenerator->AddLanguageFlagsForLinking( - flags, this->GeneratorTarget, linkLanguage, this->ConfigName); + flags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); - this->LocalGenerator->AddArchitectureFlags(flags, this->GeneratorTarget, - linkLanguage, this->ConfigName); + this->LocalGenerator->AddArchitectureFlags( + flags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); // Add target-specific linker flags. this->GetTargetLinkFlags(linkFlags, linkLanguage); { - std::unique_ptr<cmLinkLineComputer> linkLineComputer( + std::unique_ptr<cmLinkLineComputer> linkLineComputer = this->CreateLinkLineComputer( this->LocalGenerator, - this->LocalGenerator->GetStateSnapshot().GetDirectory())); + this->LocalGenerator->GetStateSnapshot().GetDirectory()); - this->AddModuleDefinitionFlag(linkLineComputer.get(), linkFlags); + this->AddModuleDefinitionFlag(linkLineComputer.get(), linkFlags, + this->GetConfigName()); } - this->LocalGenerator->AppendIPOLinkerFlags(linkFlags, this->GeneratorTarget, - this->ConfigName, linkLanguage); + this->LocalGenerator->AppendIPOLinkerFlags( + linkFlags, this->GeneratorTarget, this->GetConfigName(), linkLanguage); // Construct a list of files associated with this executable that // may need to be cleaned. @@ -451,7 +457,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) targetFullPathImport)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS( - this->ConfigName, targetFullPathImport, implib)) { + this->GetConfigName(), targetFullPathImport, implib)) { exeCleanFiles.push_back(this->LocalGenerator->MaybeConvertToRelativePath( this->LocalGenerator->GetCurrentBinaryDirectory(), implib)); } @@ -479,7 +485,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Construct the main link rule. std::vector<std::string> real_link_commands; std::string linkRuleVar = this->GeneratorTarget->GetCreateRuleVariable( - linkLanguage, this->ConfigName); + linkLanguage, this->GetConfigName()); std::string linkRule = this->GetLinkRule(linkRuleVar); std::vector<std::string> commands1; cmExpandList(linkRule, real_link_commands); @@ -506,10 +512,10 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Set path conversion for link script shells. this->LocalGenerator->SetLinkScriptShell(useLinkScript); - std::unique_ptr<cmLinkLineComputer> linkLineComputer( + std::unique_ptr<cmLinkLineComputer> linkLineComputer = this->CreateLinkLineComputer( this->LocalGenerator, - this->LocalGenerator->GetStateSnapshot().GetDirectory())); + this->LocalGenerator->GetStateSnapshot().GetDirectory()); linkLineComputer->SetForResponse(useResponseFileForLibs); linkLineComputer->SetUseWatcomQuote(useWatcomQuote); linkLineComputer->SetRelink(relink); @@ -536,7 +542,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // maybe create .def file from list of objects this->GenDefFile(real_link_commands); - std::string manifests = this->GetManifests(); + std::string manifests = this->GetManifests(this->GetConfigName()); cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GeneratorTarget->GetName().c_str(); @@ -627,7 +633,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); - cmAppend(commands, commands1); + cm::append(commands, commands1); commands1.clear(); // Add a rule to create necessary symlinks for the library. @@ -639,7 +645,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); - cmAppend(commands, commands1); + cm::append(commands, commands1); commands1.clear(); } diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 54a6606..d3f3a4f 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -9,8 +9,8 @@ #include <vector> #include <cm/memory> +#include <cmext/algorithm> -#include "cmAlgorithms.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" @@ -36,11 +36,10 @@ cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator( this->CustomCommandDriver = OnDepends; if (this->GeneratorTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY) { this->TargetNames = - this->GeneratorTarget->GetLibraryNames(this->ConfigName); + this->GeneratorTarget->GetLibraryNames(this->GetConfigName()); } - this->OSXBundleGenerator = - cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName); + this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); } @@ -69,14 +68,16 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles() break; case cmStateEnums::SHARED_LIBRARY: this->WriteSharedLibraryRules(false); - if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) { + if (this->GeneratorTarget->NeedRelinkBeforeInstall( + this->GetConfigName())) { // Write rules to link an installable version of the target. this->WriteSharedLibraryRules(true); } break; case cmStateEnums::MODULE_LIBRARY: this->WriteModuleLibraryRules(false); - if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->ConfigName)) { + if (this->GeneratorTarget->NeedRelinkBeforeInstall( + this->GetConfigName())) { // Write rules to link an installable version of the target. this->WriteModuleLibraryRules(true); } @@ -126,21 +127,21 @@ void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules() void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules() { const bool requiresDeviceLinking = requireDeviceLinking( - *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName); + *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName()); if (requiresDeviceLinking) { std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY"; this->WriteDeviceLibraryRules(linkRuleVar, false); } std::string linkLanguage = - this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); std::string linkRuleVar = this->GeneratorTarget->GetCreateRuleVariable( - linkLanguage, this->ConfigName); + linkLanguage, this->GetConfigName()); std::string extraFlags; this->LocalGenerator->GetStaticLibraryFlags( - extraFlags, cmSystemTools::UpperCase(this->ConfigName), linkLanguage, + extraFlags, cmSystemTools::UpperCase(this->GetConfigName()), linkLanguage, this->GeneratorTarget); this->WriteLibraryRules(linkRuleVar, extraFlags, false); } @@ -154,7 +155,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) if (!relink) { const bool requiresDeviceLinking = requireDeviceLinking( - *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName); + *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName()); if (requiresDeviceLinking) { std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY"; this->WriteDeviceLibraryRules(linkRuleVar, relink); @@ -162,21 +163,22 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) } std::string linkLanguage = - this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); std::string linkRuleVar = cmStrCat("CMAKE_", linkLanguage, "_CREATE_SHARED_LIBRARY"); std::string extraFlags; this->GetTargetLinkFlags(extraFlags, linkLanguage); this->LocalGenerator->AddConfigVariableFlags( - extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName); + extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->GetConfigName()); - std::unique_ptr<cmLinkLineComputer> linkLineComputer( + std::unique_ptr<cmLinkLineComputer> linkLineComputer = this->CreateLinkLineComputer( this->LocalGenerator, - this->LocalGenerator->GetStateSnapshot().GetDirectory())); + this->LocalGenerator->GetStateSnapshot().GetDirectory()); - this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags); + this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags, + this->GetConfigName()); if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) { this->LocalGenerator->AppendFlags(extraFlags, " -Wl,--no-as-needed"); @@ -188,7 +190,7 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink) { if (!relink) { const bool requiresDeviceLinking = requireDeviceLinking( - *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName); + *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName()); if (requiresDeviceLinking) { std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY"; this->WriteDeviceLibraryRules(linkRuleVar, relink); @@ -196,21 +198,22 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink) } std::string linkLanguage = - this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); std::string linkRuleVar = cmStrCat("CMAKE_", linkLanguage, "_CREATE_SHARED_MODULE"); std::string extraFlags; this->GetTargetLinkFlags(extraFlags, linkLanguage); this->LocalGenerator->AddConfigVariableFlags( - extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName); + extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->GetConfigName()); - std::unique_ptr<cmLinkLineComputer> linkLineComputer( + std::unique_ptr<cmLinkLineComputer> linkLineComputer = this->CreateLinkLineComputer( this->LocalGenerator, - this->LocalGenerator->GetStateSnapshot().GetDirectory())); + this->LocalGenerator->GetStateSnapshot().GetDirectory()); - this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags); + this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags, + this->GetConfigName()); this->WriteLibraryRules(linkRuleVar, extraFlags, relink); } @@ -218,14 +221,14 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink) void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink) { std::string linkLanguage = - this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); std::string linkRuleVar = cmStrCat("CMAKE_", linkLanguage, "_CREATE_MACOSX_FRAMEWORK"); std::string extraFlags; this->GetTargetLinkFlags(extraFlags, linkLanguage); this->LocalGenerator->AddConfigVariableFlags( - extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->ConfigName); + extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->GetConfigName()); this->WriteLibraryRules(linkRuleVar, extraFlags, relink); } @@ -331,7 +334,8 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal), output); - std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB(); + std::string targetFullPathCompilePDB = + this->ComputeTargetCompilePDB(this->GetConfigName()); std::string targetOutPathCompilePDB = this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB, cmOutputConverter::SHELL); @@ -347,7 +351,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( // Add language-specific flags. std::string langFlags; this->LocalGenerator->AddLanguageFlagsForLinking( - langFlags, this->GeneratorTarget, linkLanguage, this->ConfigName); + langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); vars.LanguageCompileFlags = langFlags.c_str(); @@ -393,7 +397,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); - cmAppend(commands, commands1); + cm::append(commands, commands1); commands1.clear(); // Compute the list of outputs. @@ -420,7 +424,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Get the language to use for linking this library. std::string linkLanguage = - this->GeneratorTarget->GetLinkerLanguage(this->ConfigName); + this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); // Make sure we have a link language. if (linkLanguage.empty()) { @@ -439,8 +443,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Create set of linking flags. std::string linkFlags; this->LocalGenerator->AppendFlags(linkFlags, extraFlags); - this->LocalGenerator->AppendIPOLinkerFlags(linkFlags, this->GeneratorTarget, - this->ConfigName, linkLanguage); + this->LocalGenerator->AppendIPOLinkerFlags( + linkFlags, this->GeneratorTarget, this->GetConfigName(), linkLanguage); // Add OSX version flags, if any. if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY || @@ -450,20 +454,20 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( } // Construct the name of the library. - this->GeneratorTarget->GetLibraryNames(this->ConfigName); + this->GeneratorTarget->GetLibraryNames(this->GetConfigName()); // Construct the full path version of the names. std::string outpath; std::string outpathImp; if (this->GeneratorTarget->IsFrameworkOnApple()) { - outpath = this->GeneratorTarget->GetDirectory(this->ConfigName); + outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName()); this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output, - outpath); + outpath, this->GetConfigName()); outpath += '/'; } else if (this->GeneratorTarget->IsCFBundleOnApple()) { - outpath = this->GeneratorTarget->GetDirectory(this->ConfigName); - this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output, - outpath); + outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName()); + this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output, outpath, + this->GetConfigName()); outpath += '/'; } else if (relink) { outpath = cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), @@ -474,23 +478,23 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( outpathImp = outpath; } } else { - outpath = this->GeneratorTarget->GetDirectory(this->ConfigName); + outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName()); cmSystemTools::MakeDirectory(outpath); outpath += '/'; if (!this->TargetNames.ImportLibrary.empty()) { outpathImp = this->GeneratorTarget->GetDirectory( - this->ConfigName, cmStateEnums::ImportLibraryArtifact); + this->GetConfigName(), cmStateEnums::ImportLibraryArtifact); cmSystemTools::MakeDirectory(outpathImp); outpathImp += '/'; } } std::string compilePdbOutputPath = - this->GeneratorTarget->GetCompilePDBDirectory(this->ConfigName); + this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName()); cmSystemTools::MakeDirectory(compilePdbOutputPath); std::string pdbOutputPath = - this->GeneratorTarget->GetPDBDirectory(this->ConfigName); + this->GeneratorTarget->GetPDBDirectory(this->GetConfigName()); cmSystemTools::MakeDirectory(pdbOutputPath); pdbOutputPath += "/"; @@ -567,7 +571,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); - cmAppend(commands, commands1); + cm::append(commands, commands1); commands1.clear(); } @@ -586,7 +590,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( targetFullPathImport)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS( - this->ConfigName, targetFullPathImport, implib)) { + this->GetConfigName(), targetFullPathImport, implib)) { libCleanFiles.insert(this->LocalGenerator->MaybeConvertToRelativePath( this->LocalGenerator->GetCurrentBinaryDirectory(), implib)); } @@ -638,7 +642,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_CREATE"); arCreateVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( - arCreateVar, linkLanguage, this->ConfigName); + arCreateVar, linkLanguage, this->GetConfigName()); if (const char* rule = this->Makefile->GetDefinition(arCreateVar)) { cmExpandList(rule, archiveCreateCommands); @@ -647,7 +651,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_APPEND"); arAppendVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( - arAppendVar, linkLanguage, this->ConfigName); + arAppendVar, linkLanguage, this->GetConfigName()); if (const char* rule = this->Makefile->GetDefinition(arAppendVar)) { cmExpandList(rule, archiveAppendCommands); @@ -656,7 +660,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_FINISH"); arFinishVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( - arFinishVar, linkLanguage, this->ConfigName); + arFinishVar, linkLanguage, this->GetConfigName()); if (const char* rule = this->Makefile->GetDefinition(arFinishVar)) { cmExpandList(rule, archiveFinishCommands); @@ -696,10 +700,10 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( std::string linkLibs; if (this->GeneratorTarget->GetType() != cmStateEnums::STATIC_LIBRARY) { - std::unique_ptr<cmLinkLineComputer> linkLineComputer( + std::unique_ptr<cmLinkLineComputer> linkLineComputer = this->CreateLinkLineComputer( this->LocalGenerator, - this->LocalGenerator->GetStateSnapshot().GetDirectory())); + this->LocalGenerator->GetStateSnapshot().GetDirectory()); linkLineComputer->SetForResponse(useResponseFileForLibs); linkLineComputer->SetUseWatcomQuote(useWatcomQuote); linkLineComputer->SetRelink(relink); @@ -723,10 +727,12 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( cmOutputConverter::SHELL); } + std::string const& aixExports = this->GetAIXExports(this->GetConfigName()); + // maybe create .def file from list of objects this->GenDefFile(real_link_commands); - std::string manifests = this->GetManifests(); + std::string manifests = this->GetManifests(this->GetConfigName()); cmRulePlaceholderExpander::RuleVariables vars; vars.TargetPDB = targetOutPathPDB.c_str(); @@ -752,6 +758,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.CMTargetType = cmState::GetTargetTypeName(this->GeneratorTarget->GetType()); vars.Language = linkLanguage.c_str(); + vars.AIXExports = aixExports.c_str(); vars.Objects = buildObjs.c_str(); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); @@ -771,7 +778,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.Target = target.c_str(); vars.LinkLibraries = linkLibs.c_str(); vars.ObjectsQuoted = buildObjs.c_str(); - if (this->GeneratorTarget->HasSOName(this->ConfigName)) { + if (this->GeneratorTarget->HasSOName(this->GetConfigName())) { vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage); vars.TargetSOName = this->TargetNames.SharedObject.c_str(); } @@ -783,8 +790,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( std::string install_name_dir; if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY) { // Get the install_name directory for the build tree. - install_name_dir = - this->GeneratorTarget->GetInstallNameDirForBuildTree(this->ConfigName); + install_name_dir = this->GeneratorTarget->GetInstallNameDirForBuildTree( + this->GetConfigName()); // Set the rule variable replacement value. if (install_name_dir.empty()) { @@ -800,10 +807,10 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Add language-specific flags. std::string langFlags; this->LocalGenerator->AddLanguageFlagsForLinking( - langFlags, this->GeneratorTarget, linkLanguage, this->ConfigName); + langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); this->LocalGenerator->AddArchitectureFlags( - langFlags, this->GeneratorTarget, linkLanguage, this->ConfigName); + langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); vars.LanguageCompileFlags = langFlags.c_str(); @@ -903,7 +910,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); - cmAppend(commands, commands1); + cm::append(commands, commands1); commands1.clear(); // Add a rule to create necessary symlinks for the library. @@ -917,7 +924,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( this->LocalGenerator->CreateCDCommand( commands1, this->Makefile->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); - cmAppend(commands, commands1); + cm::append(commands, commands1); commands1.clear(); } diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index dd8a389..451f19e 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -2,12 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmMakefileTargetGenerator.h" +#include <cassert> #include <cstdio> -#include <memory> #include <sstream> #include <utility> -#include "cmAlgorithms.h" +#include <cm/memory> +#include <cmext/algorithm> + #include "cmComputeLinkInformation.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" @@ -15,6 +17,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmLinkLineComputer.h" #include "cmLocalCommonGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" @@ -35,12 +38,7 @@ cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target) : cmCommonTargetGenerator(target) - , OSXBundleGenerator(nullptr) - , MacOSXContentGenerator(nullptr) { - this->BuildFileStream = nullptr; - this->InfoFileStream = nullptr; - this->FlagFileStream = nullptr; this->CustomCommandDriver = OnBuild; this->LocalGenerator = static_cast<cmLocalUnixMakefileGenerator3*>(target->GetLocalGenerator()); @@ -52,31 +50,28 @@ cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target) cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) { this->NoRuleMessages = cmIsOff(ruleStatus); } - MacOSXContentGenerator = new MacOSXContentGeneratorType(this); + MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this); } -cmMakefileTargetGenerator::~cmMakefileTargetGenerator() -{ - delete MacOSXContentGenerator; -} +cmMakefileTargetGenerator::~cmMakefileTargetGenerator() = default; -cmMakefileTargetGenerator* cmMakefileTargetGenerator::New( +std::unique_ptr<cmMakefileTargetGenerator> cmMakefileTargetGenerator::New( cmGeneratorTarget* tgt) { - cmMakefileTargetGenerator* result = nullptr; + std::unique_ptr<cmMakefileTargetGenerator> result; switch (tgt->GetType()) { case cmStateEnums::EXECUTABLE: - result = new cmMakefileExecutableTargetGenerator(tgt); + result = cm::make_unique<cmMakefileExecutableTargetGenerator>(tgt); break; case cmStateEnums::STATIC_LIBRARY: case cmStateEnums::SHARED_LIBRARY: case cmStateEnums::MODULE_LIBRARY: case cmStateEnums::OBJECT_LIBRARY: - result = new cmMakefileLibraryTargetGenerator(tgt); + result = cm::make_unique<cmMakefileLibraryTargetGenerator>(tgt); break; case cmStateEnums::UTILITY: - result = new cmMakefileUtilityTargetGenerator(tgt); + result = cm::make_unique<cmMakefileUtilityTargetGenerator>(tgt); break; default: return result; @@ -85,6 +80,13 @@ cmMakefileTargetGenerator* cmMakefileTargetGenerator::New( return result; } +std::string cmMakefileTargetGenerator::GetConfigName() +{ + auto const& configNames = this->LocalGenerator->GetConfigNames(); + assert(configNames.size() == 1); + return configNames.front(); +} + void cmMakefileTargetGenerator::GetTargetLinkFlags( std::string& flags, const std::string& linkLanguage) { @@ -92,17 +94,18 @@ void cmMakefileTargetGenerator::GetTargetLinkFlags( flags, this->GeneratorTarget->GetSafeProperty("LINK_FLAGS")); std::string linkFlagsConfig = - cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(this->ConfigName)); + cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(this->GetConfigName())); this->LocalGenerator->AppendFlags( flags, this->GeneratorTarget->GetSafeProperty(linkFlagsConfig)); std::vector<std::string> opts; - this->GeneratorTarget->GetLinkOptions(opts, this->ConfigName, linkLanguage); + this->GeneratorTarget->GetLinkOptions(opts, this->GetConfigName(), + linkLanguage); // LINK_OPTIONS are escaped. this->LocalGenerator->AppendCompileOptions(flags, opts); this->LocalGenerator->AppendPositionIndependentLinkerFlags( - flags, this->GeneratorTarget, this->ConfigName, linkLanguage); + flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage); } void cmMakefileTargetGenerator::CreateRuleFile() @@ -128,9 +131,9 @@ void cmMakefileTargetGenerator::CreateRuleFile() // Open the rule file. This should be copy-if-different because the // rules may depend on this file itself. - this->BuildFileStream = - new cmGeneratedFileStream(this->BuildFileNameFull, false, - this->GlobalGenerator->GetMakefileEncoding()); + this->BuildFileStream = cm::make_unique<cmGeneratedFileStream>( + this->BuildFileNameFull, false, + this->GlobalGenerator->GetMakefileEncoding()); if (!this->BuildFileStream) { return; } @@ -152,12 +155,12 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() // Evaluates generator expressions and expands prop_value auto evaluatedFiles = - [this](const char* prop_value) -> std::vector<std::string> { + [this](const std::string& prop_value) -> std::vector<std::string> { std::vector<std::string> files; - cmExpandList( - cmGeneratorExpression::Evaluate(prop_value, this->LocalGenerator, - this->ConfigName, this->GeneratorTarget), - files); + cmExpandList(cmGeneratorExpression::Evaluate( + prop_value, this->LocalGenerator, this->GetConfigName(), + this->GeneratorTarget), + files); return files; }; @@ -187,12 +190,13 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() // First generate the object rule files. Save a list of all object // files for this target. std::vector<cmSourceFile const*> customCommands; - this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName); + this->GeneratorTarget->GetCustomCommands(customCommands, + this->GetConfigName()); std::string currentBinDir = this->LocalGenerator->GetCurrentBinaryDirectory(); for (cmSourceFile const* sf : customCommands) { - cmCustomCommandGenerator ccg(*sf->GetCustomCommand(), this->ConfigName, - this->LocalGenerator); + cmCustomCommandGenerator ccg(*sf->GetCustomCommand(), + this->GetConfigName(), this->LocalGenerator); this->GenerateCustomRuleFile(ccg); if (clean) { const std::vector<std::string>& outputs = ccg.GetOutputs(); @@ -215,12 +219,14 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() std::vector<cmCustomCommand> buildEventCommands = this->GeneratorTarget->GetPreBuildCommands(); - cmAppend(buildEventCommands, this->GeneratorTarget->GetPreLinkCommands()); - cmAppend(buildEventCommands, - this->GeneratorTarget->GetPostBuildCommands()); + cm::append(buildEventCommands, + this->GeneratorTarget->GetPreLinkCommands()); + cm::append(buildEventCommands, + this->GeneratorTarget->GetPostBuildCommands()); for (const auto& be : buildEventCommands) { - cmCustomCommandGenerator beg(be, this->ConfigName, this->LocalGenerator); + cmCustomCommandGenerator beg(be, this->GetConfigName(), + this->LocalGenerator); const std::vector<std::string>& byproducts = beg.GetByproducts(); for (std::string const& byproduct : byproducts) { this->CleanFiles.insert( @@ -230,17 +236,19 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() } } std::vector<cmSourceFile const*> headerSources; - this->GeneratorTarget->GetHeaderSources(headerSources, this->ConfigName); + this->GeneratorTarget->GetHeaderSources(headerSources, + this->GetConfigName()); this->OSXBundleGenerator->GenerateMacOSXContentStatements( - headerSources, this->MacOSXContentGenerator); + headerSources, this->MacOSXContentGenerator.get(), this->GetConfigName()); std::vector<cmSourceFile const*> extraSources; - this->GeneratorTarget->GetExtraSources(extraSources, this->ConfigName); + this->GeneratorTarget->GetExtraSources(extraSources, this->GetConfigName()); this->OSXBundleGenerator->GenerateMacOSXContentStatements( - extraSources, this->MacOSXContentGenerator); + extraSources, this->MacOSXContentGenerator.get(), this->GetConfigName()); const char* pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION"); std::vector<cmSourceFile const*> externalObjects; - this->GeneratorTarget->GetExternalObjects(externalObjects, this->ConfigName); + this->GeneratorTarget->GetExternalObjects(externalObjects, + this->GetConfigName()); for (cmSourceFile const* sf : externalObjects) { auto const& objectFileName = sf->GetFullPath(); if (!cmSystemTools::StringEndsWith(objectFileName, pchExtension)) { @@ -248,7 +256,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() } } std::vector<cmSourceFile const*> objectSources; - this->GeneratorTarget->GetObjectSources(objectSources, this->ConfigName); + this->GeneratorTarget->GetObjectSources(objectSources, + this->GetConfigName()); for (cmSourceFile const* sf : objectSources) { // Generate this object file's rule file. this->WriteObjectRuleFiles(*sf); @@ -299,9 +308,9 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() // rules may depend on this file itself. this->FlagFileNameFull = cmStrCat(this->TargetBuildDirectoryFull, "/flags.make"); - this->FlagFileStream = - new cmGeneratedFileStream(this->FlagFileNameFull, false, - this->GlobalGenerator->GetMakefileEncoding()); + this->FlagFileStream = cm::make_unique<cmGeneratedFileStream>( + this->FlagFileNameFull, false, + this->GlobalGenerator->GetMakefileEncoding()); if (!this->FlagFileStream) { return; } @@ -334,9 +343,9 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() } for (std::string const& language : languages) { - std::string flags = this->GetFlags(language); - std::string defines = this->GetDefines(language); - std::string includes = this->GetIncludes(language); + std::string flags = this->GetFlags(language, this->GetConfigName()); + std::string defines = this->GetDefines(language, this->GetConfigName()); + std::string includes = this->GetIncludes(language, this->GetConfigName()); // Escape comment characters so they do not terminate assignment. cmSystemTools::ReplaceString(flags, "#", "\\#"); cmSystemTools::ReplaceString(defines, "#", "\\#"); @@ -348,7 +357,7 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() } void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( - cmSourceFile const& source, const char* pkgloc) + cmSourceFile const& source, const char* pkgloc, const std::string& config) { // Skip OS X content when not building a Framework or Bundle. if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) { @@ -356,7 +365,8 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( } std::string macdir = - this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc); + this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc, + config); // Get the input file location. std::string const& input = source.GetFullPath(); @@ -451,7 +461,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // generate the depend scanning rule this->WriteObjectDependRules(source, depends); - std::string config = this->LocalGenerator->GetConfigName(); + std::string config = this->GetConfigName(); std::string configUpper = cmSystemTools::UpperCase(config); // Add precompile headers dependencies @@ -593,16 +603,17 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( { std::string targetFullPathReal; std::string targetFullPathPDB; - std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB(); + std::string targetFullPathCompilePDB = + this->ComputeTargetCompilePDB(this->GetConfigName()); if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE || this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY || this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY || this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) { targetFullPathReal = this->GeneratorTarget->GetFullPath( - this->ConfigName, cmStateEnums::RuntimeBinaryArtifact, true); - targetFullPathPDB = - cmStrCat(this->GeneratorTarget->GetPDBDirectory(this->ConfigName), '/', - this->GeneratorTarget->GetPDBName(this->ConfigName)); + this->GetConfigName(), cmStateEnums::RuntimeBinaryArtifact, true); + targetFullPathPDB = cmStrCat( + this->GeneratorTarget->GetPDBDirectory(this->GetConfigName()), '/', + this->GeneratorTarget->GetPDBName(this->GetConfigName())); } targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat( @@ -708,13 +719,15 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string workingDirectory = cmSystemTools::CollapseFullPath( this->LocalGenerator->GetCurrentBinaryDirectory()); compileCommand.replace(compileCommand.find(langFlags), langFlags.size(), - this->GetFlags(lang)); + this->GetFlags(lang, this->GetConfigName())); std::string langDefines = std::string("$(") + lang + "_DEFINES)"; compileCommand.replace(compileCommand.find(langDefines), - langDefines.size(), this->GetDefines(lang)); + langDefines.size(), + this->GetDefines(lang, this->GetConfigName())); std::string langIncludes = std::string("$(") + lang + "_INCLUDES)"; compileCommand.replace(compileCommand.find(langIncludes), - langIncludes.size(), this->GetIncludes(lang)); + langIncludes.size(), + this->GetIncludes(lang, this->GetConfigName())); const char* eliminate[] = { this->Makefile->GetDefinition("CMAKE_START_TEMP_FILE"), @@ -769,7 +782,13 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( } if (tidy && *tidy) { run_iwyu += " --tidy="; - run_iwyu += this->LocalGenerator->EscapeForShell(tidy); + const char* driverMode = this->Makefile->GetDefinition( + "CMAKE_" + lang + "_CLANG_TIDY_DRIVER_MODE"); + if (!(driverMode && *driverMode)) { + driverMode = lang == "C" ? "gcc" : "g++"; + } + run_iwyu += this->LocalGenerator->EscapeForShell( + cmStrCat(tidy, ";--extra-arg-before=--driver-mode=", driverMode)); } if (cpplint && *cpplint) { run_iwyu += " --cpplint="; @@ -823,7 +842,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( this->LocalGenerator->CreateCDCommand( compileCommands, this->LocalGenerator->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); - cmAppend(commands, compileCommands); + cm::append(commands, compileCommands); } // Check for extra outputs created by the compilation. @@ -882,7 +901,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( preprocessCommands, this->LocalGenerator->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); - cmAppend(commands, preprocessCommands); + cm::append(commands, preprocessCommands); } else { std::string cmd = cmStrCat("$(CMAKE_COMMAND) -E cmake_unimplemented_variable ", @@ -926,7 +945,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( this->LocalGenerator->CreateCDCommand( assemblyCommands, this->LocalGenerator->GetCurrentBinaryDirectory(), this->LocalGenerator->GetBinaryDirectory()); - cmAppend(commands, assemblyCommands); + cm::append(commands, assemblyCommands); } else { std::string cmd = cmStrCat("$(CMAKE_COMMAND) -E cmake_unimplemented_variable ", @@ -1036,7 +1055,8 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() this->InfoFileNameFull = cmStrCat(dir, "/DependInfo.cmake"); this->InfoFileNameFull = this->LocalGenerator->ConvertToFullPath(this->InfoFileNameFull); - this->InfoFileStream = new cmGeneratedFileStream(this->InfoFileNameFull); + this->InfoFileStream = + cm::make_unique<cmGeneratedFileStream>(this->InfoFileNameFull); if (!this->InfoFileStream) { return; } @@ -1068,7 +1088,8 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() << "# Targets to which this target links.\n" << "set(CMAKE_TARGET_LINKED_INFO_FILES\n"; /* clang-format on */ - std::vector<std::string> dirs = this->GetLinkedTargetDirectories(); + std::vector<std::string> dirs = + this->GetLinkedTargetDirectories(this->GetConfigName()); for (std::string const& d : dirs) { *this->InfoFileStream << " \"" << d << "/DependInfo.cmake\"\n"; } @@ -1171,9 +1192,9 @@ void cmMakefileTargetGenerator::DriveCustomCommands( sources, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); for (cmSourceFile* source : sources) { if (cmCustomCommand* cc = source->GetCustomCommand()) { - cmCustomCommandGenerator ccg(*cc, this->ConfigName, + cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), this->LocalGenerator); - cmAppend(depends, ccg.GetOutputs()); + cm::append(depends, ccg.GetOutputs()); } } } @@ -1410,7 +1431,7 @@ void cmMakefileTargetGenerator::WriteTargetDriverRule( } // Make sure the extra files are built. - cmAppend(depends, this->ExtraFiles); + cm::append(depends, this->ExtraFiles); } // Write the driver rule. @@ -1429,10 +1450,10 @@ void cmMakefileTargetGenerator::AppendTargetDepends( } // Loop over all library dependencies. - const std::string& cfg = this->LocalGenerator->GetConfigName(); + const std::string& cfg = this->GetConfigName(); if (cmComputeLinkInformation* cli = this->GeneratorTarget->GetLinkInformation(cfg)) { - cmAppend(depends, cli->GetDepends()); + cm::append(depends, cli->GetDepends()); } } @@ -1448,7 +1469,7 @@ void cmMakefileTargetGenerator::AppendObjectDepends( } // Add dependencies on the external object files. - cmAppend(depends, this->ExternalObjects); + cm::append(depends, this->ExternalObjects); // Add a dependency on the rule file itself. this->LocalGenerator->AppendRuleDepend(depends, @@ -1474,13 +1495,13 @@ void cmMakefileTargetGenerator::AppendLinkDepends( // Add a dependency on user-specified manifest files, if any. std::vector<cmSourceFile const*> manifest_srcs; - this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName); + this->GeneratorTarget->GetManifests(manifest_srcs, this->GetConfigName()); for (cmSourceFile const* manifest_src : manifest_srcs) { depends.push_back(manifest_src->GetFullPath()); } // Add user-specified dependencies. - this->GeneratorTarget->GetLinkDepends(depends, this->ConfigName, + this->GeneratorTarget->GetLinkDepends(depends, this->GetConfigName(), linkLanguage); } @@ -1488,10 +1509,11 @@ std::string cmMakefileTargetGenerator::GetLinkRule( const std::string& linkRuleVar) { std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar); - if (this->GeneratorTarget->HasImplibGNUtoMS(this->ConfigName)) { - std::string ruleVar = cmStrCat( - "CMAKE_", this->GeneratorTarget->GetLinkerLanguage(this->ConfigName), - "_GNUtoMS_RULE"); + if (this->GeneratorTarget->HasImplibGNUtoMS(this->GetConfigName())) { + std::string ruleVar = + cmStrCat("CMAKE_", + this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()), + "_GNUtoMS_RULE"); if (const char* rule = this->Makefile->GetDefinition(ruleVar)) { linkRule += rule; } @@ -1501,9 +1523,9 @@ std::string cmMakefileTargetGenerator::GetLinkRule( void cmMakefileTargetGenerator::CloseFileStreams() { - delete this->BuildFileStream; - delete this->InfoFileStream; - delete this->FlagFileStream; + this->BuildFileStream.reset(); + this->InfoFileStream.reset(); + this->FlagFileStream.reset(); } void cmMakefileTargetGenerator::CreateLinkScript( @@ -1612,7 +1634,8 @@ std::string cmMakefileTargetGenerator::CreateResponseFile( return responseFileName; } -cmLinkLineComputer* cmMakefileTargetGenerator::CreateLinkLineComputer( +std::unique_ptr<cmLinkLineComputer> +cmMakefileTargetGenerator::CreateLinkLineComputer( cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) { if (this->Makefile->IsOn("MSVC60")) { @@ -1630,7 +1653,7 @@ void cmMakefileTargetGenerator::CreateLinkLibs( std::string frameworkPath; std::string linkPath; cmComputeLinkInformation* pcli = - this->GeneratorTarget->GetLinkInformation(this->ConfigName); + this->GeneratorTarget->GetLinkInformation(this->GetConfigName()); this->LocalGenerator->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, frameworkPath, linkPath); linkLibs = frameworkPath + linkPath + linkLibs; @@ -1638,9 +1661,10 @@ void cmMakefileTargetGenerator::CreateLinkLibs( if (useResponseFile && linkLibs.find_first_not_of(' ') != std::string::npos) { // Lookup the response file reference flag. - std::string responseFlagVar = cmStrCat( - "CMAKE_", this->GeneratorTarget->GetLinkerLanguage(this->ConfigName), - "_RESPONSE_FILE_LINK_FLAG"); + std::string responseFlagVar = + cmStrCat("CMAKE_", + this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()), + "_RESPONSE_FILE_LINK_FLAG"); const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar); if (!responseFlag) { responseFlag = "@"; @@ -1675,9 +1699,10 @@ void cmMakefileTargetGenerator::CreateObjectLists( this->WriteObjectsStrings(object_strings, responseFileLimit); // Lookup the response file reference flag. - std::string responseFlagVar = cmStrCat( - "CMAKE_", this->GeneratorTarget->GetLinkerLanguage(this->ConfigName), - "_RESPONSE_FILE_LINK_FLAG"); + std::string responseFlagVar = + cmStrCat("CMAKE_", + this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()), + "_RESPONSE_FILE_LINK_FLAG"); const char* responseFlag = this->Makefile->GetDefinition(responseFlagVar); if (!responseFlag) { responseFlag = "@"; @@ -1716,7 +1741,8 @@ void cmMakefileTargetGenerator::CreateObjectLists( } void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags, - const std::string& lang) + const std::string& lang, + const std::string& /*config*/) { std::string responseVar = cmStrCat("CMAKE_", lang, "_USE_RESPONSE_FILE_FOR_INCLUDES"); @@ -1724,11 +1750,11 @@ void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags, std::vector<std::string> includes; this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, - lang, this->ConfigName); + lang, this->GetConfigName()); std::string includeFlags = this->LocalGenerator->GetIncludeFlags( includes, this->GeneratorTarget, lang, false, useResponseFile, - this->ConfigName); + this->GetConfigName()); if (includeFlags.empty()) { return; } diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 7b9c7a5..ec6b314 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -34,10 +34,15 @@ class cmMakefileTargetGenerator : public cmCommonTargetGenerator public: // constructor to set the ivars cmMakefileTargetGenerator(cmGeneratorTarget* target); + cmMakefileTargetGenerator(const cmMakefileTargetGenerator&) = delete; ~cmMakefileTargetGenerator() override; + cmMakefileTargetGenerator& operator=(const cmMakefileTargetGenerator&) = + delete; + // construct using this factory call - static cmMakefileTargetGenerator* New(cmGeneratorTarget* tgt); + static std::unique_ptr<cmMakefileTargetGenerator> New( + cmGeneratorTarget* tgt); /* the main entry point for this class. Writes the Makefiles associated with this target */ @@ -52,6 +57,8 @@ public: cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; } + std::string GetConfigName(); + protected: void GetTargetLinkFlags(std::string& flags, const std::string& linkLanguage); @@ -81,7 +88,8 @@ protected: { } - void operator()(cmSourceFile const& source, const char* pkgloc) override; + void operator()(cmSourceFile const& source, const char* pkgloc, + const std::string& config) override; private: cmMakefileTargetGenerator* Generator; @@ -137,7 +145,7 @@ protected: std::vector<std::string>& makefile_commands, std::vector<std::string>& makefile_depends); - cmLinkLineComputer* CreateLinkLineComputer( + std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer( cmOutputConverter* outputConverter, cmStateDirectory const& stateDir); /** Create a response file with the given set of options. Returns @@ -163,7 +171,8 @@ protected: /** Add commands for generate def files */ void GenDefFile(std::vector<std::string>& real_link_commands); - void AddIncludeFlags(std::string& flags, const std::string& lang) override; + void AddIncludeFlags(std::string& flags, const std::string& lang, + const std::string& config) override; virtual void CloseFileStreams(); cmLocalUnixMakefileGenerator3* LocalGenerator; @@ -191,11 +200,11 @@ protected: std::string TargetBuildDirectoryFull; // the stream for the build file - cmGeneratedFileStream* BuildFileStream; + std::unique_ptr<cmGeneratedFileStream> BuildFileStream; // the stream for the flag file std::string FlagFileNameFull; - cmGeneratedFileStream* FlagFileStream; + std::unique_ptr<cmGeneratedFileStream> FlagFileStream; class StringList : public std::vector<std::string> { }; @@ -203,7 +212,7 @@ protected: // the stream for the info file std::string InfoFileNameFull; - cmGeneratedFileStream* InfoFileStream; + std::unique_ptr<cmGeneratedFileStream> InfoFileStream; // files to clean std::set<std::string> CleanFiles; @@ -232,7 +241,7 @@ protected: // macOS content info. std::set<std::string> MacContentFolders; std::unique_ptr<cmOSXBundleGenerator> OSXBundleGenerator; - MacOSXContentGeneratorType* MacOSXContentGenerator; + std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator; }; #endif diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx index 1625e4f..6c18e48 100644 --- a/Source/cmMakefileUtilityTargetGenerator.cxx +++ b/Source/cmMakefileUtilityTargetGenerator.cxx @@ -22,8 +22,7 @@ cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator( : cmMakefileTargetGenerator(target) { this->CustomCommandDriver = OnUtility; - this->OSXBundleGenerator = - cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName); + this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); } diff --git a/Source/cmMarkAsAdvancedCommand.cxx b/Source/cmMarkAsAdvancedCommand.cxx index ca46e14..45043fa 100644 --- a/Source/cmMarkAsAdvancedCommand.cxx +++ b/Source/cmMarkAsAdvancedCommand.cxx @@ -4,8 +4,11 @@ #include "cmExecutionStatus.h" #include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmPolicies.h" #include "cmState.h" #include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmake.h" @@ -28,14 +31,63 @@ bool cmMarkAsAdvancedCommand(std::vector<std::string> const& args, } i = 1; } + + cmMakefile& mf = status.GetMakefile(); + cmState* state = mf.GetState(); + for (; i < args.size(); ++i) { std::string const& variable = args[i]; - cmState* state = status.GetMakefile().GetState(); - if (!state->GetCacheEntryValue(variable)) { - status.GetMakefile().GetCMakeInstance()->AddCacheEntry( - variable, nullptr, nullptr, cmStateEnums::UNINITIALIZED); - overwrite = true; + + bool issueMessage = false; + bool oldBehavior = false; + bool ignoreVariable = false; + switch (mf.GetPolicyStatus(cmPolicies::CMP0102)) { + case cmPolicies::WARN: + if (mf.PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0102")) { + if (!state->GetCacheEntryValue(variable)) { + issueMessage = true; + } + } + CM_FALLTHROUGH; + case cmPolicies::OLD: + oldBehavior = true; + break; + case cmPolicies::NEW: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + if (!state->GetCacheEntryValue(variable)) { + ignoreVariable = true; + } + break; + } + + // First see if we should issue a message about CMP0102 + if (issueMessage) { + std::string err = cmStrCat( + "Policy CMP0102 is not set: The variable named \"", variable, + "\" is not in the cache. This results in an empty cache entry which " + "is no longer created when policy CMP0102 is set to NEW. Run \"cmake " + "--help-policy CMP0102\" for policy details. Use the cmake_policy " + "command to set the policy and suppress this warning."); + mf.IssueMessage(MessageType::AUTHOR_WARNING, err); } + + // If it's not in the cache and we're using the new behavior, nothing to + // see here. + if (ignoreVariable) { + continue; + } + + // Check if we want the old behavior of making a dummy cache entry. + if (oldBehavior) { + if (!state->GetCacheEntryValue(variable)) { + status.GetMakefile().GetCMakeInstance()->AddCacheEntry( + variable, nullptr, nullptr, cmStateEnums::UNINITIALIZED); + overwrite = true; + } + } + + // We need a cache entry to do this. if (!state->GetCacheEntryValue(variable)) { cmSystemTools::Error("This should never happen..."); return false; diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx index 96a6386..bf8183b 100644 --- a/Source/cmMessageCommand.cxx +++ b/Source/cmMessageCommand.cxx @@ -3,6 +3,11 @@ #include "cmMessageCommand.h" #include <cassert> +#include <utility> + +#include <cm/string_view> + +#include "cm_static_string_view.hxx" #include "cmExecutionStatus.h" #include "cmMakefile.h" @@ -13,6 +18,55 @@ #include "cmSystemTools.h" #include "cmake.h" +namespace { + +enum class CheckingType +{ + UNDEFINED, + CHECK_START, + CHECK_PASS, + CHECK_FAIL +}; + +std::string IndentText(std::string text, cmMakefile& mf) +{ + auto indent = + cmJoin(cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_INDENT")), ""); + + const auto showContext = mf.GetCMakeInstance()->GetShowLogContext() || + mf.IsOn("CMAKE_MESSAGE_CONTEXT_SHOW"); + if (showContext) { + auto context = cmJoin( + cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_CONTEXT")), "."); + if (!context.empty()) { + indent.insert(0u, cmStrCat("["_s, context, "] "_s)); + } + } + + if (!indent.empty()) { + cmSystemTools::ReplaceString(text, "\n", "\n" + indent); + text.insert(0u, indent); + } + return text; +} + +void ReportCheckResult(cm::string_view what, std::string result, + cmMakefile& mf) +{ + if (mf.GetCMakeInstance()->HasCheckInProgress()) { + auto text = mf.GetCMakeInstance()->GetTopCheckInProgressMessage() + " - " + + std::move(result); + mf.DisplayStatus(IndentText(std::move(text), mf), -1); + } else { + mf.GetMessenger()->DisplayMessage( + MessageType::AUTHOR_WARNING, + cmStrCat("Ignored "_s, what, " without CHECK_START"_s), + mf.GetBacktrace()); + } +} + +} // anonymous namespace + // cmLibraryCommand bool cmMessageCommand(std::vector<std::string> const& args, cmExecutionStatus& status) @@ -21,11 +75,15 @@ bool cmMessageCommand(std::vector<std::string> const& args, status.SetError("called with incorrect number of arguments"); return false; } + + auto& mf = status.GetMakefile(); + auto i = args.cbegin(); auto type = MessageType::MESSAGE; auto fatal = false; auto level = cmake::LogLevel::LOG_UNDEFINED; + auto checkingType = CheckingType::UNDEFINED; if (*i == "SEND_ERROR") { type = MessageType::FATAL_ERROR; level = cmake::LogLevel::LOG_ERROR; @@ -40,19 +98,30 @@ bool cmMessageCommand(std::vector<std::string> const& args, level = cmake::LogLevel::LOG_WARNING; ++i; } else if (*i == "AUTHOR_WARNING") { - if (status.GetMakefile().IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") && - !status.GetMakefile().IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) { + if (mf.IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") && + !mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) { fatal = true; type = MessageType::AUTHOR_ERROR; level = cmake::LogLevel::LOG_ERROR; - } else if (!status.GetMakefile().IsOn( - "CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) { + } else if (!mf.IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) { type = MessageType::AUTHOR_WARNING; level = cmake::LogLevel::LOG_WARNING; } else { return true; } ++i; + } else if (*i == "CHECK_START") { + level = cmake::LogLevel::LOG_STATUS; + checkingType = CheckingType::CHECK_START; + ++i; + } else if (*i == "CHECK_PASS") { + level = cmake::LogLevel::LOG_STATUS; + checkingType = CheckingType::CHECK_PASS; + ++i; + } else if (*i == "CHECK_FAIL") { + level = cmake::LogLevel::LOG_STATUS; + checkingType = CheckingType::CHECK_FAIL; + ++i; } else if (*i == "STATUS") { level = cmake::LogLevel::LOG_STATUS; ++i; @@ -66,12 +135,12 @@ bool cmMessageCommand(std::vector<std::string> const& args, level = cmake::LogLevel::LOG_TRACE; ++i; } else if (*i == "DEPRECATION") { - if (status.GetMakefile().IsOn("CMAKE_ERROR_DEPRECATED")) { + if (mf.IsOn("CMAKE_ERROR_DEPRECATED")) { fatal = true; type = MessageType::DEPRECATION_ERROR; level = cmake::LogLevel::LOG_ERROR; - } else if (!status.GetMakefile().IsSet("CMAKE_WARN_DEPRECATED") || - status.GetMakefile().IsOn("CMAKE_WARN_DEPRECATED")) { + } else if (!mf.IsSet("CMAKE_WARN_DEPRECATED") || + mf.IsOn("CMAKE_WARN_DEPRECATED")) { type = MessageType::DEPRECATION_WARNING; level = cmake::LogLevel::LOG_WARNING; } else { @@ -89,10 +158,19 @@ bool cmMessageCommand(std::vector<std::string> const& args, assert("Message log level expected to be set" && level != cmake::LogLevel::LOG_UNDEFINED); - auto desiredLevel = status.GetMakefile().GetCMakeInstance()->GetLogLevel(); + auto desiredLevel = mf.GetCMakeInstance()->GetLogLevel(); assert("Expected a valid log level here" && desiredLevel != cmake::LogLevel::LOG_UNDEFINED); + // Command line option takes precedence over the cache variable + if (!mf.GetCMakeInstance()->WasLogLevelSetViaCLI()) { + const auto desiredLevelFromCache = + cmake::StringToLogLevel(mf.GetSafeDefinition("CMAKE_MESSAGE_LOG_LEVEL")); + if (desiredLevelFromCache != cmake::LogLevel::LOG_UNDEFINED) { + desiredLevel = desiredLevelFromCache; + } + } + if (desiredLevel < level) { // Suppress the message return true; @@ -100,37 +178,42 @@ bool cmMessageCommand(std::vector<std::string> const& args, auto message = cmJoin(cmMakeRange(i, args.cend()), ""); - if (cmake::LogLevel::LOG_NOTICE <= level) { - // Check if any indentation has requested: - // `CMAKE_MESSAGE_INDENT` is a list of "padding" pieces - // to be joined and prepended to the message lines. - auto indent = cmJoin(cmExpandedList(status.GetMakefile().GetSafeDefinition( - "CMAKE_MESSAGE_INDENT")), - ""); - // Make every line of the `message` indented - // NOTE Can't reuse `cmDocumentationFormatter::PrintPreformatted` - // here cuz it appends `\n` to the EOM ;-( - cmSystemTools::ReplaceString(message, "\n", "\n" + indent); - message = indent + message; - } - switch (level) { case cmake::LogLevel::LOG_ERROR: case cmake::LogLevel::LOG_WARNING: // we've overridden the message type, above, so display it directly - status.GetMakefile().GetMessenger()->DisplayMessage( - type, message, status.GetMakefile().GetBacktrace()); + mf.GetMessenger()->DisplayMessage(type, message, mf.GetBacktrace()); break; case cmake::LogLevel::LOG_NOTICE: - cmSystemTools::Message(message); + cmSystemTools::Message(IndentText(message, mf)); break; case cmake::LogLevel::LOG_STATUS: + switch (checkingType) { + case CheckingType::CHECK_START: + mf.DisplayStatus(IndentText(message, mf), -1); + mf.GetCMakeInstance()->PushCheckInProgressMessage(message); + break; + + case CheckingType::CHECK_PASS: + ReportCheckResult("CHECK_PASS"_s, message, mf); + break; + + case CheckingType::CHECK_FAIL: + ReportCheckResult("CHECK_FAIL"_s, message, mf); + break; + + default: + mf.DisplayStatus(IndentText(message, mf), -1); + break; + } + break; + case cmake::LogLevel::LOG_VERBOSE: case cmake::LogLevel::LOG_DEBUG: case cmake::LogLevel::LOG_TRACE: - status.GetMakefile().DisplayStatus(message, -1); + mf.DisplayStatus(IndentText(message, mf), -1); break; default: diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index a458cac..062c46c 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -11,8 +11,8 @@ #include <utility> #include <cm/memory> +#include <cm/vector> -#include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmCustomCommand.h" // IWYU pragma: keep #include "cmCustomCommandGenerator.h" @@ -41,33 +41,25 @@ cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator( cmGeneratorTarget* target) : cmNinjaTargetGenerator(target) - , TargetLinkLanguage("") { - this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName()); - if (target->GetType() == cmStateEnums::EXECUTABLE) { - this->TargetNames = this->GetGeneratorTarget()->GetExecutableNames( - GetLocalGenerator()->GetConfigName()); - } else { - this->TargetNames = this->GetGeneratorTarget()->GetLibraryNames( - GetLocalGenerator()->GetConfigName()); - } - if (target->GetType() != cmStateEnums::OBJECT_LIBRARY) { // on Windows the output dir is already needed at compile time // ensure the directory exists (OutDir test) - EnsureDirectoryExists(target->GetDirectory(this->GetConfigName())); + for (auto const& config : this->GetConfigNames()) { + EnsureDirectoryExists(target->GetDirectory(config)); + } } - this->OSXBundleGenerator = - cm::make_unique<cmOSXBundleGenerator>(target, this->GetConfigName()); + this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target); this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); } cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator() = default; -void cmNinjaNormalTargetGenerator::Generate() +void cmNinjaNormalTargetGenerator::Generate(const std::string& config) { - if (this->TargetLinkLanguage.empty()) { + 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()); @@ -75,25 +67,48 @@ void cmNinjaNormalTargetGenerator::Generate() } // Write the rules for each language. - this->WriteLanguagesRules(); + this->WriteLanguagesRules(config); // Write the build statements - this->WriteObjectBuildStatements(); + bool firstForConfig = true; + for (auto const& fileConfig : this->GetConfigNames()) { + if (!this->GetGlobalGenerator() + ->GetCrossConfigs(fileConfig) + .count(config)) { + continue; + } + this->WriteObjectBuildStatements(config, fileConfig, firstForConfig); + firstForConfig = false; + } if (this->GetGeneratorTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) { - this->WriteObjectLibStatement(); + this->WriteObjectLibStatement(config); } else { - // If this target has cuda language link inputs, and we need to do - // device linking - this->WriteDeviceLinkStatement(); - this->WriteLinkStatement(); + firstForConfig = true; + for (auto const& fileConfig : this->GetConfigNames()) { + if (!this->GetGlobalGenerator() + ->GetCrossConfigs(fileConfig) + .count(config)) { + continue; + } + // If this target has cuda language link inputs, and we need to do + // device linking + this->WriteDeviceLinkStatement(config, fileConfig, firstForConfig); + this->WriteLinkStatement(config, fileConfig, firstForConfig); + firstForConfig = false; + } + } + if (this->GetGlobalGenerator()->EnableCrossConfigBuild()) { + this->GetGlobalGenerator()->AddTargetAlias( + this->GetTargetName(), this->GetGeneratorTarget(), "all"); } // Find ADDITIONAL_CLEAN_FILES - this->AdditionalCleanFiles(); + this->AdditionalCleanFiles(config); } -void cmNinjaNormalTargetGenerator::WriteLanguagesRules() +void cmNinjaNormalTargetGenerator::WriteLanguagesRules( + const std::string& config) { #ifdef NINJA_GEN_VERBOSE_FILES cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream()); @@ -106,8 +121,7 @@ void cmNinjaNormalTargetGenerator::WriteLanguagesRules() // Write rules for languages compiled in this target. std::set<std::string> languages; std::vector<cmSourceFile const*> sourceFiles; - this->GetGeneratorTarget()->GetObjectSources( - sourceFiles, this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE")); + this->GetGeneratorTarget()->GetObjectSources(sourceFiles, config); for (cmSourceFile const* sf : sourceFiles) { std::string const lang = sf->GetLanguage(); if (!lang.empty()) { @@ -115,7 +129,7 @@ void cmNinjaNormalTargetGenerator::WriteLanguagesRules() } } for (std::string const& language : languages) { - this->WriteLanguageRules(language); + this->WriteLanguageRules(language, config); } } @@ -139,22 +153,26 @@ const char* cmNinjaNormalTargetGenerator::GetVisibleTypeName() const } } -std::string cmNinjaNormalTargetGenerator::LanguageLinkerRule() const +std::string cmNinjaNormalTargetGenerator::LanguageLinkerRule( + const std::string& config) const { - return this->TargetLinkLanguage + "_" + + return this->TargetLinkLanguage(config) + "_" + cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) + "_LINKER__" + cmGlobalNinjaGenerator::EncodeRuleName( - this->GetGeneratorTarget()->GetName()); + this->GetGeneratorTarget()->GetName()) + + "_" + config; } -std::string cmNinjaNormalTargetGenerator::LanguageLinkerDeviceRule() const +std::string cmNinjaNormalTargetGenerator::LanguageLinkerDeviceRule( + const std::string& config) const { - return this->TargetLinkLanguage + "_" + + return this->TargetLinkLanguage(config) + "_" + cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) + "_DEVICE_LINKER__" + cmGlobalNinjaGenerator::EncodeRuleName( - this->GetGeneratorTarget()->GetName()); + this->GetGeneratorTarget()->GetName()) + + "_" + config; } struct cmNinjaRemoveNoOpCommands @@ -165,9 +183,10 @@ struct cmNinjaRemoveNoOpCommands } }; -void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile) +void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule( + bool useResponseFile, const std::string& config) { - cmNinjaRule rule(this->LanguageLinkerDeviceRule()); + cmNinjaRule rule(this->LanguageLinkerDeviceRule(config)); if (!this->GetGlobalGenerator()->HasRule(rule.Name)) { cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); @@ -236,35 +255,40 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile) } // If there is no ranlib the command will be ":". Skip it. - cmEraseIf(linkCmds, cmNinjaRemoveNoOpCommands()); + cm::erase_if(linkCmds, cmNinjaRemoveNoOpCommands()); rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds); // Write the linker rule with response file if needed. - rule.Comment = cmStrCat("Rule for linking ", this->TargetLinkLanguage, ' ', - this->GetVisibleTypeName(), '.'); - rule.Description = cmStrCat("Linking ", this->TargetLinkLanguage, ' ', - this->GetVisibleTypeName(), " $TARGET_FILE"); + rule.Comment = + cmStrCat("Rule for linking ", this->TargetLinkLanguage(config), ' ', + this->GetVisibleTypeName(), '.'); + rule.Description = + cmStrCat("Linking ", this->TargetLinkLanguage(config), ' ', + this->GetVisibleTypeName(), " $TARGET_FILE"); rule.Restat = "$RESTAT"; this->GetGlobalGenerator()->AddRule(rule); } } -void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile) +void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, + const std::string& config) { cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType(); - std::string linkRuleName = this->LanguageLinkerRule(); + std::string linkRuleName = this->LanguageLinkerRule(config); if (!this->GetGlobalGenerator()->HasRule(linkRuleName)) { cmNinjaRule rule(std::move(linkRuleName)); cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(targetType); - vars.Language = this->TargetLinkLanguage.c_str(); + std::string lang = this->TargetLinkLanguage(config); + vars.Language = config.c_str(); + vars.AIXExports = "$AIX_EXPORTS"; - if (this->TargetLinkLanguage == "Swift") { + if (this->TargetLinkLanguage(config) == "Swift") { vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME"; vars.SwiftModule = "$SWIFT_MODULE"; vars.SwiftModuleName = "$SWIFT_MODULE_NAME"; @@ -278,7 +302,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile) std::string responseFlag; - std::string cmakeVarLang = cmStrCat("CMAKE_", this->TargetLinkLanguage); + std::string cmakeVarLang = + cmStrCat("CMAKE_", this->TargetLinkLanguage(config)); // build response file name std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG"; @@ -304,7 +329,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile) rule.RspContent = "$in_newline"; } rule.RspContent += " $LINK_PATH $LINK_LIBRARIES"; - if (this->TargetLinkLanguage == "Swift") { + if (this->TargetLinkLanguage(config) == "Swift") { vars.SwiftSources = responseFlag.c_str(); } else { vars.Objects = responseFlag.c_str(); @@ -359,7 +384,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile) this->GetLocalGenerator()->CreateRulePlaceholderExpander()); // Rule for linking library/executable. - std::vector<std::string> linkCmds = this->ComputeLinkCmd(); + std::vector<std::string> linkCmds = this->ComputeLinkCmd(config); for (std::string& linkCmd : linkCmds) { linkCmd = cmStrCat(launcher, linkCmd); rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), @@ -367,22 +392,25 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile) } // If there is no ranlib the command will be ":". Skip it. - cmEraseIf(linkCmds, cmNinjaRemoveNoOpCommands()); + cm::erase_if(linkCmds, cmNinjaRemoveNoOpCommands()); linkCmds.insert(linkCmds.begin(), "$PRE_LINK"); linkCmds.emplace_back("$POST_BUILD"); rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds); // Write the linker rule with response file if needed. - rule.Comment = cmStrCat("Rule for linking ", this->TargetLinkLanguage, ' ', - this->GetVisibleTypeName(), '.'); - rule.Description = cmStrCat("Linking ", this->TargetLinkLanguage, ' ', - this->GetVisibleTypeName(), " $TARGET_FILE"); + rule.Comment = + cmStrCat("Rule for linking ", this->TargetLinkLanguage(config), ' ', + this->GetVisibleTypeName(), '.'); + rule.Description = + cmStrCat("Linking ", this->TargetLinkLanguage(config), ' ', + this->GetVisibleTypeName(), " $TARGET_FILE"); rule.Restat = "$RESTAT"; this->GetGlobalGenerator()->AddRule(rule); } - if (this->TargetNames.Output != this->TargetNames.Real && + auto const tgtNames = this->TargetNames(config); + if (tgtNames.Output != tgtNames.Real && !this->GetGeneratorTarget()->IsFrameworkOnApple()) { std::string cmakeCommand = this->GetLocalGenerator()->ConvertToOutputFormat( @@ -441,7 +469,8 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd() return linkCmds; } -std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd() +std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd( + const std::string& config) { std::vector<std::string> linkCmds; cmMakefile* mf = this->GetMakefile(); @@ -450,14 +479,14 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd() // this occurs when things like IPO is enabled, and we need to use the // CMAKE_<lang>_CREATE_STATIC_LIBRARY_IPO define instead. std::string linkCmdVar = this->GetGeneratorTarget()->GetCreateRuleVariable( - this->TargetLinkLanguage, this->GetConfigName()); + this->TargetLinkLanguage(config), config); const char* linkCmd = mf->GetDefinition(linkCmdVar); if (linkCmd) { std::string linkCmdStr = linkCmd; - if (this->GetGeneratorTarget()->HasImplibGNUtoMS(this->ConfigName)) { - std::string ruleVar = cmStrCat( - "CMAKE_", this->GeneratorTarget->GetLinkerLanguage(this->ConfigName), - "_GNUtoMS_RULE"); + if (this->GetGeneratorTarget()->HasImplibGNUtoMS(config)) { + std::string ruleVar = + cmStrCat("CMAKE_", this->GeneratorTarget->GetLinkerLanguage(config), + "_GNUtoMS_RULE"); if (const char* rule = this->Makefile->GetDefinition(ruleVar)) { linkCmdStr += rule; } @@ -469,9 +498,8 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd() cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL), " -E __run_co_compile --lwyu="); cmGeneratorTarget& gt = *this->GetGeneratorTarget(); - const std::string cfgName = this->GetConfigName(); std::string targetOutputReal = this->ConvertToNinjaPath( - gt.GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact, + gt.GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact, /*realname=*/true)); cmakeCommand += targetOutputReal; linkCmds.push_back(std::move(cmakeCommand)); @@ -486,25 +514,25 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd() std::string cmakeCommand = this->GetLocalGenerator()->ConvertToOutputFormat( cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); - linkCmds.push_back(cmakeCommand + " -E remove $TARGET_FILE"); + linkCmds.push_back(cmakeCommand + " -E rm -f $TARGET_FILE"); } // TODO: Use ARCHIVE_APPEND for archives over a certain size. { - std::string linkCmdVar = - cmStrCat("CMAKE_", this->TargetLinkLanguage, "_ARCHIVE_CREATE"); + std::string linkCmdVar = cmStrCat( + "CMAKE_", this->TargetLinkLanguage(config), "_ARCHIVE_CREATE"); linkCmdVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( - linkCmdVar, this->TargetLinkLanguage, this->GetConfigName()); + linkCmdVar, this->TargetLinkLanguage(config), config); std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar); cmExpandList(linkCmd, linkCmds); } { - std::string linkCmdVar = - cmStrCat("CMAKE_", this->TargetLinkLanguage, "_ARCHIVE_FINISH"); + std::string linkCmdVar = cmStrCat( + "CMAKE_", this->TargetLinkLanguage(config), "_ARCHIVE_FINISH"); linkCmdVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( - linkCmdVar, this->TargetLinkLanguage, this->GetConfigName()); + linkCmdVar, this->TargetLinkLanguage(config), config); std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar); cmExpandList(linkCmd, linkCmds); @@ -523,19 +551,28 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd() linkCmds.push_back(cmakeCommand + " -E touch $TARGET_FILE"); } #endif - return linkCmds; - } + } break; case cmStateEnums::SHARED_LIBRARY: case cmStateEnums::MODULE_LIBRARY: + break; case cmStateEnums::EXECUTABLE: + if (this->TargetLinkLanguage(config) == "Swift") { + if (this->GeneratorTarget->IsExecutableWithExports()) { + const std::string flags = + this->Makefile->GetSafeDefinition("CMAKE_EXE_EXPORTS_Swift_FLAG"); + cmExpandList(flags, linkCmds); + } + } break; default: assert(false && "Unexpected target type"); } - return std::vector<std::string>(); + return linkCmds; } -void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() +void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement( + const std::string& config, const std::string& fileConfig, + bool firstForConfig) { cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator(); if (!globalGen->GetLanguageEnabled("CUDA")) { @@ -545,7 +582,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() cmGeneratorTarget* genTarget = this->GetGeneratorTarget(); bool requiresDeviceLinking = requireDeviceLinking( - *this->GeneratorTarget, *this->GetLocalGenerator(), this->ConfigName); + *this->GeneratorTarget, *this->GetLocalGenerator(), config); if (!requiresDeviceLinking) { return; } @@ -558,24 +595,53 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() std::string const& objExt = this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION"); - std::string const cfgName = this->GetConfigName(); - std::string const targetOutputReal = ConvertToNinjaPath( - genTarget->ObjectDirectory + "cmake_device_link" + objExt); + std::string targetOutputDir = + cmStrCat(this->GetLocalGenerator()->GetTargetDirectory(genTarget), + globalGen->ConfigDirectory(config), "/"); + targetOutputDir = globalGen->ExpandCFGIntDir(targetOutputDir, config); + + std::string targetOutputReal = + ConvertToNinjaPath(targetOutputDir + "cmake_device_link" + objExt); + + std::string targetOutputImplib = ConvertToNinjaPath( + genTarget->GetFullPath(config, cmStateEnums::ImportLibraryArtifact)); + + if (config != fileConfig) { + std::string targetOutputFileConfigDir = + cmStrCat(this->GetLocalGenerator()->GetTargetDirectory(genTarget), + globalGen->ConfigDirectory(fileConfig), "/"); + targetOutputFileConfigDir = + globalGen->ExpandCFGIntDir(targetOutputDir, fileConfig); + if (targetOutputDir == targetOutputFileConfigDir) { + return; + } - std::string const targetOutputImplib = ConvertToNinjaPath( - genTarget->GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact)); + if (!genTarget->GetFullName(config, cmStateEnums::ImportLibraryArtifact) + .empty() && + !genTarget + ->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact) + .empty() && + targetOutputImplib == + ConvertToNinjaPath(genTarget->GetFullPath( + fileConfig, cmStateEnums::ImportLibraryArtifact))) { + return; + } + } + if (firstForConfig) { + globalGen->GetByproductsForCleanTarget(config).push_back(targetOutputReal); + } this->DeviceLinkObject = targetOutputReal; // Write comments. - cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream()); + cmGlobalNinjaGenerator::WriteDivider(this->GetCommonFileStream()); const cmStateEnums::TargetType targetType = genTarget->GetType(); - this->GetBuildFileStream() << "# Device Link build statements for " - << cmState::GetTargetTypeName(targetType) - << " target " << this->GetTargetName() << "\n\n"; + this->GetCommonFileStream() << "# Device Link build statements for " + << cmState::GetTargetTypeName(targetType) + << " target " << this->GetTargetName() << "\n\n"; // Compute the comment. - cmNinjaBuild build(this->LanguageLinkerDeviceRule()); + cmNinjaBuild build(this->LanguageLinkerDeviceRule(config)); build.Comment = cmStrCat("Link the ", this->GetVisibleTypeName(), ' ', targetOutputReal); @@ -584,14 +650,15 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() // Compute outputs. build.Outputs.push_back(targetOutputReal); // Compute specific libraries to link with. - build.ExplicitDeps = this->GetObjects(); - build.ImplicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage); + build.ExplicitDeps = this->GetObjects(config); + build.ImplicitDeps = + this->ComputeLinkDeps(this->TargetLinkLanguage(config), config); std::string frameworkPath; std::string linkPath; - std::string createRule = genTarget->GetCreateRuleVariable( - this->TargetLinkLanguage, this->GetConfigName()); + std::string createRule = + genTarget->GetCreateRuleVariable(this->TargetLinkLanguage(config), config); const bool useWatcomQuote = this->GetMakefile()->IsOn(createRule + "_USE_WATCOM_QUOTE"); cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator(); @@ -605,17 +672,17 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() this->GetLocalGenerator()->GetStateSnapshot().GetDirectory(), globalGen)); linkLineComputer->SetUseWatcomQuote(useWatcomQuote); + linkLineComputer->SetUseNinjaMulti(globalGen->IsMultiConfig()); localGen.GetTargetFlags( - linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"], - vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, genTarget); + linkLineComputer.get(), config, vars["LINK_LIBRARIES"], vars["FLAGS"], + vars["LINK_FLAGS"], frameworkPath, linkPath, genTarget); this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars); - vars["LINK_FLAGS"] = - cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]); + vars["LINK_FLAGS"] = globalGen->EncodeLiteral(vars["LINK_FLAGS"]); - vars["MANIFESTS"] = this->GetManifests(); + vars["MANIFESTS"] = this->GetManifests(config); vars["LINK_PATH"] = frameworkPath + linkPath; @@ -624,24 +691,25 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() // code between the Makefile executable and library generators. if (targetType == cmStateEnums::EXECUTABLE) { std::string t = vars["FLAGS"]; - localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, cfgName); + localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, config); vars["FLAGS"] = t; } else { std::string t = vars["ARCH_FLAGS"]; - localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, cfgName); + localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, config); vars["ARCH_FLAGS"] = t; t.clear(); localGen.AddLanguageFlagsForLinking(t, genTarget, cudaLinkLanguage, - cfgName); + config); vars["LANGUAGE_COMPILE_FLAGS"] = t; } - if (genTarget->HasSOName(cfgName)) { + auto const tgtNames = this->TargetNames(config); + if (genTarget->HasSOName(config)) { vars["SONAME_FLAG"] = - this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage); - vars["SONAME"] = this->TargetNames.SharedObject; + this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage(config)); + vars["SONAME"] = tgtNames.SharedObject; if (targetType == cmStateEnums::SHARED_LIBRARY) { std::string install_dir = - this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName); + this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(config); if (!install_dir.empty()) { vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat( install_dir, cmOutputConverter::SHELL); @@ -649,25 +717,28 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() } } - if (!this->TargetNames.ImportLibrary.empty()) { + if (!tgtNames.ImportLibrary.empty()) { const std::string impLibPath = localGen.ConvertToOutputFormat( targetOutputImplib, cmOutputConverter::SHELL); vars["TARGET_IMPLIB"] = impLibPath; EnsureParentDirectoryExists(impLibPath); } - const std::string objPath = GetGeneratorTarget()->GetSupportDirectory(); + const std::string objPath = + cmStrCat(GetGeneratorTarget()->GetSupportDirectory(), + globalGen->ConfigDirectory(config)); + vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat( this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL); EnsureDirectoryExists(objPath); - this->SetMsvcTargetPdbVariable(vars); + this->SetMsvcTargetPdbVariable(vars, config); + std::string& linkLibraries = vars["LINK_LIBRARIES"]; + std::string& link_path = vars["LINK_PATH"]; if (globalGen->IsGCCOnWindows()) { // ar.exe can't handle backslashes in rsp files (implicitly used by gcc) - std::string& linkLibraries = vars["LINK_LIBRARIES"]; std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/'); - std::string& link_path = vars["LINK_PATH"]; std::replace(link_path.begin(), link_path.end(), '\\', '/'); } @@ -675,65 +746,100 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() // do not check if the user has explicitly forced a response file. int const commandLineLengthLimit = static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) - - globalGen->GetRuleCmdLength(this->LanguageLinkerDeviceRule()); + globalGen->GetRuleCmdLength(this->LanguageLinkerDeviceRule(config)); build.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") + genTarget->GetName() + ".rsp"); // Gather order-only dependencies. - this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(), - build.OrderOnlyDeps); + this->GetLocalGenerator()->AppendTargetDepends( + this->GetGeneratorTarget(), build.OrderOnlyDeps, config, config); // Write the build statement for this target. bool usedResponseFile = false; - globalGen->WriteBuild(this->GetBuildFileStream(), build, + globalGen->WriteBuild(this->GetCommonFileStream(), build, commandLineLengthLimit, &usedResponseFile); - this->WriteDeviceLinkRule(usedResponseFile); + this->WriteDeviceLinkRule(usedResponseFile, config); } -void cmNinjaNormalTargetGenerator::WriteLinkStatement() +void cmNinjaNormalTargetGenerator::WriteLinkStatement( + const std::string& config, const std::string& fileConfig, + bool firstForConfig) { cmMakefile* mf = this->GetMakefile(); cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator(); cmGeneratorTarget* gt = this->GetGeneratorTarget(); - const std::string cfgName = this->GetConfigName(); - std::string targetOutput = ConvertToNinjaPath(gt->GetFullPath(cfgName)); + std::string targetOutput = ConvertToNinjaPath(gt->GetFullPath(config)); std::string targetOutputReal = ConvertToNinjaPath( - gt->GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact, + gt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact, /*realname=*/true)); std::string targetOutputImplib = ConvertToNinjaPath( - gt->GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact)); + gt->GetFullPath(config, cmStateEnums::ImportLibraryArtifact)); + if (config != fileConfig) { + if (targetOutput == ConvertToNinjaPath(gt->GetFullPath(fileConfig))) { + return; + } + if (targetOutputReal == + ConvertToNinjaPath(gt->GetFullPath(fileConfig, + cmStateEnums::RuntimeBinaryArtifact, + /*realname=*/true))) { + return; + } + if (!gt->GetFullName(config, cmStateEnums::ImportLibraryArtifact) + .empty() && + !gt->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact) + .empty() && + targetOutputImplib == + ConvertToNinjaPath(gt->GetFullPath( + fileConfig, cmStateEnums::ImportLibraryArtifact))) { + return; + } + } + + auto const tgtNames = this->TargetNames(config); if (gt->IsAppBundleOnApple()) { // Create the app bundle - std::string outpath = gt->GetDirectory(cfgName); - this->OSXBundleGenerator->CreateAppBundle(this->TargetNames.Output, - outpath); + std::string outpath = gt->GetDirectory(config); + this->OSXBundleGenerator->CreateAppBundle(tgtNames.Output, outpath, + config); // Calculate the output path - targetOutput = cmStrCat(outpath, '/', this->TargetNames.Output); + targetOutput = cmStrCat(outpath, '/', tgtNames.Output); targetOutput = this->ConvertToNinjaPath(targetOutput); - targetOutputReal = cmStrCat(outpath, '/', this->TargetNames.Real); + targetOutputReal = cmStrCat(outpath, '/', tgtNames.Real); targetOutputReal = this->ConvertToNinjaPath(targetOutputReal); } else if (gt->IsFrameworkOnApple()) { // Create the library framework. - this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output, - gt->GetDirectory(cfgName)); + + cmOSXBundleGenerator::SkipParts bundleSkipParts; + if (globalGen->GetName() == "Ninja Multi-Config") { + const auto postFix = this->GeneratorTarget->GetFilePostfix(config); + // Skip creating Info.plist when there are multiple configurations, and + // the current configuration has a postfix. The non-postfix configuration + // Info.plist can be used by all the other configurations. + if (!postFix.empty()) { + bundleSkipParts.infoPlist = true; + } + } + + this->OSXBundleGenerator->CreateFramework( + tgtNames.Output, gt->GetDirectory(config), config, bundleSkipParts); } else if (gt->IsCFBundleOnApple()) { // Create the core foundation bundle. - this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output, - gt->GetDirectory(cfgName)); + this->OSXBundleGenerator->CreateCFBundle(tgtNames.Output, + gt->GetDirectory(config), config); } // Write comments. - cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream()); + cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig)); const cmStateEnums::TargetType targetType = gt->GetType(); - this->GetBuildFileStream() + this->GetImplFileStream(fileConfig) << "# Link build statements for " << cmState::GetTargetTypeName(targetType) << " target " << this->GetTargetName() << "\n\n"; - cmNinjaBuild linkBuild(this->LanguageLinkerRule()); + cmNinjaBuild linkBuild(this->LanguageLinkerRule(config)); cmNinjaVars& vars = linkBuild.Variables; // Compute the comment. @@ -742,11 +848,14 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // Compute outputs. linkBuild.Outputs.push_back(targetOutputReal); + if (firstForConfig) { + globalGen->GetByproductsForCleanTarget(config).push_back(targetOutputReal); + } - if (this->TargetLinkLanguage == "Swift") { - vars["SWIFT_LIBRARY_NAME"] = [this]() -> std::string { + if (this->TargetLinkLanguage(config) == "Swift") { + vars["SWIFT_LIBRARY_NAME"] = [this, config]() -> std::string { cmGeneratorTarget::Names targetNames = - this->GetGeneratorTarget()->GetLibraryNames(this->GetConfigName()); + this->GetGeneratorTarget()->GetLibraryNames(config); return targetNames.Base; }(); @@ -776,18 +885,17 @@ 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(gt->GetSupportDirectory() + - "/output-file-map.json"), - cmOutputConverter::SHELL); + this->ConvertToNinjaPath(map), cmOutputConverter::SHELL); - vars["SWIFT_SOURCES"] = [this]() -> std::string { + vars["SWIFT_SOURCES"] = [this, config]() -> std::string { std::vector<cmSourceFile const*> sources; std::stringstream oss; - this->GetGeneratorTarget()->GetObjectSources(sources, - this->GetConfigName()); + this->GetGeneratorTarget()->GetObjectSources(sources, config); cmLocalGenerator const* LocalGen = this->GetLocalGenerator(); for (const auto& source : sources) { oss << " " @@ -801,27 +909,28 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // Since we do not perform object builds, compute the // defines/flags/includes here so that they can be passed along // appropriately. - vars["DEFINES"] = this->GetDefines("Swift"); - vars["FLAGS"] = this->GetFlags("Swift"); - vars["INCLUDES"] = this->GetIncludes("Swift"); + vars["DEFINES"] = this->GetDefines("Swift", config); + vars["FLAGS"] = this->GetFlags("Swift", config); + vars["INCLUDES"] = this->GetIncludes("Swift", config); } // Compute specific libraries to link with. - if (this->TargetLinkLanguage == "Swift") { + if (this->TargetLinkLanguage(config) == "Swift") { std::vector<cmSourceFile const*> sources; - gt->GetObjectSources(sources, this->GetConfigName()); + gt->GetObjectSources(sources, config); for (const auto& source : sources) { linkBuild.Outputs.push_back( - this->ConvertToNinjaPath(this->GetObjectFilePath(source))); + this->ConvertToNinjaPath(this->GetObjectFilePath(source, config))); linkBuild.ExplicitDeps.push_back( this->ConvertToNinjaPath(this->GetSourceFilePath(source))); } linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]); } else { - linkBuild.ExplicitDeps = this->GetObjects(); + linkBuild.ExplicitDeps = this->GetObjects(config); } - linkBuild.ImplicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage); + linkBuild.ImplicitDeps = + this->ComputeLinkDeps(this->TargetLinkLanguage(config), config); if (!this->DeviceLinkObject.empty()) { linkBuild.ExplicitDeps.push_back(this->DeviceLinkObject); @@ -831,39 +940,42 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string linkPath; std::string createRule = - gt->GetCreateRuleVariable(this->TargetLinkLanguage, this->GetConfigName()); + gt->GetCreateRuleVariable(this->TargetLinkLanguage(config), config); bool useWatcomQuote = mf->IsOn(createRule + "_USE_WATCOM_QUOTE"); cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator(); vars["TARGET_FILE"] = localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL); - std::unique_ptr<cmLinkLineComputer> linkLineComputer( + std::unique_ptr<cmLinkLineComputer> linkLineComputer = globalGen->CreateLinkLineComputer( this->GetLocalGenerator(), - this->GetLocalGenerator()->GetStateSnapshot().GetDirectory())); + this->GetLocalGenerator()->GetStateSnapshot().GetDirectory()); linkLineComputer->SetUseWatcomQuote(useWatcomQuote); + linkLineComputer->SetUseNinjaMulti(globalGen->IsMultiConfig()); - localGen.GetTargetFlags(linkLineComputer.get(), this->GetConfigName(), + localGen.GetTargetFlags(linkLineComputer.get(), config, vars["LINK_LIBRARIES"], vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, gt); // Add OS X version flags, if any. if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY || this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) { - this->AppendOSXVerFlag(vars["LINK_FLAGS"], this->TargetLinkLanguage, - "COMPATIBILITY", true); - this->AppendOSXVerFlag(vars["LINK_FLAGS"], this->TargetLinkLanguage, - "CURRENT", false); + this->AppendOSXVerFlag(vars["LINK_FLAGS"], + this->TargetLinkLanguage(config), "COMPATIBILITY", + true); + this->AppendOSXVerFlag(vars["LINK_FLAGS"], + this->TargetLinkLanguage(config), "CURRENT", false); } this->addPoolNinjaVariable("JOB_POOL_LINK", gt, vars); - this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"]); - vars["LINK_FLAGS"] = - cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]); + this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"], + config); + vars["LINK_FLAGS"] = globalGen->EncodeLiteral(vars["LINK_FLAGS"]); - vars["MANIFESTS"] = this->GetManifests(); + vars["MANIFESTS"] = this->GetManifests(config); + vars["AIX_EXPORTS"] = this->GetAIXExports(config); vars["LINK_PATH"] = frameworkPath + linkPath; std::string lwyuFlags; @@ -876,23 +988,26 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // code between the Makefile executable and library generators. if (targetType == cmStateEnums::EXECUTABLE) { std::string t = vars["FLAGS"]; - localGen.AddArchitectureFlags(t, gt, TargetLinkLanguage, cfgName); + localGen.AddArchitectureFlags(t, gt, this->TargetLinkLanguage(config), + config); t += lwyuFlags; vars["FLAGS"] = t; } else { std::string t = vars["ARCH_FLAGS"]; - localGen.AddArchitectureFlags(t, gt, TargetLinkLanguage, cfgName); + localGen.AddArchitectureFlags(t, gt, this->TargetLinkLanguage(config), + config); vars["ARCH_FLAGS"] = t; t.clear(); t += lwyuFlags; - localGen.AddLanguageFlagsForLinking(t, gt, TargetLinkLanguage, cfgName); + localGen.AddLanguageFlagsForLinking( + t, gt, this->TargetLinkLanguage(config), config); vars["LANGUAGE_COMPILE_FLAGS"] = t; } - if (gt->HasSOName(cfgName)) { - vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage); - vars["SONAME"] = this->TargetNames.SharedObject; + if (gt->HasSOName(config)) { + vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage(config)); + vars["SONAME"] = tgtNames.SharedObject; if (targetType == cmStateEnums::SHARED_LIBRARY) { - std::string install_dir = gt->GetInstallNameDirForBuildTree(cfgName); + std::string install_dir = gt->GetInstallNameDirForBuildTree(config); if (!install_dir.empty()) { vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat( install_dir, cmOutputConverter::SHELL); @@ -902,17 +1017,21 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() cmNinjaDeps byproducts; - if (!this->TargetNames.ImportLibrary.empty()) { + if (!tgtNames.ImportLibrary.empty()) { const std::string impLibPath = localGen.ConvertToOutputFormat( targetOutputImplib, cmOutputConverter::SHELL); vars["TARGET_IMPLIB"] = impLibPath; EnsureParentDirectoryExists(impLibPath); - if (gt->HasImportLibrary(cfgName)) { + if (gt->HasImportLibrary(config)) { byproducts.push_back(targetOutputImplib); + if (firstForConfig) { + globalGen->GetByproductsForCleanTarget(config).push_back( + targetOutputImplib); + } } } - if (!this->SetMsvcTargetPdbVariable(vars)) { + if (!this->SetMsvcTargetPdbVariable(vars, config)) { // It is common to place debug symbols at a specific place, // so we need a plain target name in the rule available. std::string prefix; @@ -927,16 +1046,17 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() vars["TARGET_PDB"] = base + suffix + dbg_suffix; } - const std::string objPath = gt->GetSupportDirectory(); + const std::string objPath = + cmStrCat(gt->GetSupportDirectory(), globalGen->ConfigDirectory(config)); vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat( this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL); EnsureDirectoryExists(objPath); + std::string& linkLibraries = vars["LINK_LIBRARIES"]; + std::string& link_path = vars["LINK_PATH"]; if (globalGen->IsGCCOnWindows()) { // ar.exe can't handle backslashes in rsp files (implicitly used by gcc) - std::string& linkLibraries = vars["LINK_LIBRARIES"]; std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/'); - std::string& link_path = vars["LINK_PATH"]; std::replace(link_path.begin(), link_path.end(), '\\', '/'); } @@ -947,23 +1067,30 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::vector<std::string> preLinkCmdLines; std::vector<std::string> postBuildCmdLines; - std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines, - &preLinkCmdLines, - &postBuildCmdLines }; - - for (unsigned i = 0; i != 3; ++i) { - for (cmCustomCommand const& cc : *cmdLists[i]) { - cmCustomCommandGenerator ccg(cc, cfgName, this->GetLocalGenerator()); - localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]); - std::vector<std::string> const& ccByproducts = ccg.GetByproducts(); - std::transform(ccByproducts.begin(), ccByproducts.end(), - std::back_inserter(byproducts), MapToNinjaPath()); + + if (config == fileConfig) { + std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines, + &preLinkCmdLines, + &postBuildCmdLines }; + + for (unsigned i = 0; i != 3; ++i) { + for (cmCustomCommand const& cc : *cmdLists[i]) { + cmCustomCommandGenerator ccg(cc, config, this->GetLocalGenerator()); + localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]); + std::vector<std::string> const& ccByproducts = ccg.GetByproducts(); + std::transform(ccByproducts.begin(), ccByproducts.end(), + std::back_inserter(byproducts), MapToNinjaPath()); + std::transform( + ccByproducts.begin(), ccByproducts.end(), + std::back_inserter(globalGen->GetByproductsForCleanTarget()), + MapToNinjaPath()); + } } } // maybe create .def file from list of objects cmGeneratorTarget::ModuleDefinitionInfo const* mdi = - gt->GetModuleDefinitionInfo(this->GetConfigName()); + gt->GetModuleDefinitionInfo(config); if (mdi && mdi->DefFileGenerated) { std::string cmakeCommand = this->GetLocalGenerator()->ConvertToOutputFormat( @@ -989,7 +1116,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() cmGeneratedFileStream fout(obj_list_file); if (mdi->WindowsExportAllSymbols) { - cmNinjaDeps objs = this->GetObjects(); + cmNinjaDeps objs = this->GetObjects(config); for (std::string const& obj : objs) { if (cmHasLiteralSuffix(obj, ".obj")) { fout << obj << "\n"; @@ -1024,7 +1151,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() symlinkVars["POST_BUILD"] = postBuildCmdLine; } - std::string cmakeVarLang = cmStrCat("CMAKE_", this->TargetLinkLanguage); + std::string cmakeVarLang = + cmStrCat("CMAKE_", this->TargetLinkLanguage(config)); // build response file name std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG"; @@ -1032,8 +1160,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar); bool const lang_supports_response = - !(this->TargetLinkLanguage == "RC" || - (this->TargetLinkLanguage == "CUDA" && !flag)); + !(this->TargetLinkLanguage(config) == "RC" || + (this->TargetLinkLanguage(config) == "CUDA" && !flag)); int commandLineLengthLimit = -1; if (!lang_supports_response || !this->ForceResponseFile()) { commandLineLengthLimit = @@ -1045,18 +1173,19 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() gt->GetName() + ".rsp"); // Gather order-only dependencies. - this->GetLocalGenerator()->AppendTargetDepends(gt, linkBuild.OrderOnlyDeps); + this->GetLocalGenerator()->AppendTargetDepends(gt, linkBuild.OrderOnlyDeps, + config, fileConfig); // Add order-only dependencies on versioning symlinks of shared libs we link. if (!this->GeneratorTarget->IsDLLPlatform()) { if (cmComputeLinkInformation* cli = - this->GeneratorTarget->GetLinkInformation(this->GetConfigName())) { + this->GeneratorTarget->GetLinkInformation(config)) { for (auto const& item : cli->GetItems()) { if (item.Target && item.Target->GetType() == cmStateEnums::SHARED_LIBRARY && !item.Target->IsFrameworkOnApple()) { - std::string const& lib = this->ConvertToNinjaPath( - item.Target->GetFullPath(this->GetConfigName())); + std::string const& lib = + this->ConvertToNinjaPath(item.Target->GetFullPath(config)); if (std::find(linkBuild.ImplicitDeps.begin(), linkBuild.ImplicitDeps.end(), lib) == linkBuild.ImplicitDeps.end()) { @@ -1077,24 +1206,27 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // Write the build statement for this target. bool usedResponseFile = false; - globalGen->WriteBuild(this->GetBuildFileStream(), linkBuild, + globalGen->WriteBuild(this->GetImplFileStream(fileConfig), linkBuild, commandLineLengthLimit, &usedResponseFile); - this->WriteLinkRule(usedResponseFile); + this->WriteLinkRule(usedResponseFile, config); if (symlinkNeeded) { if (targetType == cmStateEnums::EXECUTABLE) { cmNinjaBuild build("CMAKE_SYMLINK_EXECUTABLE"); build.Comment = "Create executable symlink " + targetOutput; build.Outputs.push_back(targetOutput); + if (firstForConfig) { + globalGen->GetByproductsForCleanTarget(config).push_back(targetOutput); + } build.ExplicitDeps.push_back(targetOutputReal); build.Variables = std::move(symlinkVars); - globalGen->WriteBuild(this->GetBuildFileStream(), build); + globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build); } else { cmNinjaBuild build("CMAKE_SYMLINK_LIBRARY"); build.Comment = "Create library symlink " + targetOutput; std::string const soName = this->ConvertToNinjaPath( - this->GetTargetFilePath(this->TargetNames.SharedObject)); + this->GetTargetFilePath(tgtNames.SharedObject, config)); // If one link has to be created. if (targetOutputReal == soName || targetOutput == soName) { symlinkVars["SONAME"] = @@ -1103,33 +1235,58 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() } else { symlinkVars["SONAME"].clear(); build.Outputs.push_back(soName); + if (firstForConfig) { + globalGen->GetByproductsForCleanTarget(config).push_back(soName); + } } build.Outputs.push_back(targetOutput); + if (firstForConfig) { + globalGen->GetByproductsForCleanTarget(config).push_back(targetOutput); + } build.ExplicitDeps.push_back(targetOutputReal); build.Variables = std::move(symlinkVars); - globalGen->WriteBuild(this->GetBuildFileStream(), build); + globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build); } } // Add aliases for the file name and the target name. - globalGen->AddTargetAlias(this->TargetNames.Output, gt); - globalGen->AddTargetAlias(this->GetTargetName(), gt); + globalGen->AddTargetAlias(tgtNames.Output, gt, config); + globalGen->AddTargetAlias(this->GetTargetName(), gt, config); } -void cmNinjaNormalTargetGenerator::WriteObjectLibStatement() +void cmNinjaNormalTargetGenerator::WriteObjectLibStatement( + const std::string& config) { // Write a phony output that depends on all object files. { cmNinjaBuild build("phony"); build.Comment = "Object library " + this->GetTargetName(); this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(), - build.Outputs); - build.ExplicitDeps = this->GetObjects(); - this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build); + build.Outputs, config); + this->GetLocalGenerator()->AppendTargetOutputs( + this->GetGeneratorTarget(), + this->GetGlobalGenerator()->GetByproductsForCleanTarget(config), config); + build.ExplicitDeps = this->GetObjects(config); + this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(), build); } // Add aliases for the target name. - this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), - this->GetGeneratorTarget()); + this->GetGlobalGenerator()->AddTargetAlias( + this->GetTargetName(), this->GetGeneratorTarget(), config); +} + +cmGeneratorTarget::Names cmNinjaNormalTargetGenerator::TargetNames( + const std::string& config) const +{ + if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) { + return this->GeneratorTarget->GetExecutableNames(config); + } + return this->GeneratorTarget->GetLibraryNames(config); +} + +std::string cmNinjaNormalTargetGenerator::TargetLinkLanguage( + const std::string& config) const +{ + return this->GeneratorTarget->GetLinkerLanguage(config); } diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h index ebc1268..9de99b9 100644 --- a/Source/cmNinjaNormalTargetGenerator.h +++ b/Source/cmNinjaNormalTargetGenerator.h @@ -17,30 +17,33 @@ public: cmNinjaNormalTargetGenerator(cmGeneratorTarget* target); ~cmNinjaNormalTargetGenerator() override; - void Generate() override; + void Generate(const std::string& config) override; private: - std::string LanguageLinkerRule() const; - std::string LanguageLinkerDeviceRule() const; + std::string LanguageLinkerRule(const std::string& config) const; + std::string LanguageLinkerDeviceRule(const std::string& config) const; const char* GetVisibleTypeName() const; - void WriteLanguagesRules(); + void WriteLanguagesRules(const std::string& config); - void WriteLinkRule(bool useResponseFile); - void WriteDeviceLinkRule(bool useResponseFile); + void WriteLinkRule(bool useResponseFile, const std::string& config); + void WriteDeviceLinkRule(bool useResponseFile, const std::string& config); - void WriteLinkStatement(); - void WriteDeviceLinkStatement(); + void WriteLinkStatement(const std::string& config, + const std::string& fileConfig, bool firstForConfig); + void WriteDeviceLinkStatement(const std::string& config, + const std::string& fileConfig, + bool firstForConfig); - void WriteObjectLibStatement(); + void WriteObjectLibStatement(const std::string& config); - std::vector<std::string> ComputeLinkCmd(); + std::vector<std::string> ComputeLinkCmd(const std::string& config); std::vector<std::string> ComputeDeviceLinkCmd(); private: // Target name info. - cmGeneratorTarget::Names TargetNames; - std::string TargetLinkLanguage; + cmGeneratorTarget::Names TargetNames(const std::string& config) const; + std::string TargetLinkLanguage(const std::string& config) const; std::string DeviceLinkObject; }; diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 0aab912..0e1136f 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -10,11 +10,11 @@ #include <utility> #include <cm/memory> +#include <cmext/algorithm> #include "cm_jsoncpp_value.h" #include "cm_jsoncpp_writer.h" -#include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmCustomCommandGenerator.h" #include "cmGeneratedFileStream.h" @@ -58,19 +58,27 @@ std::unique_ptr<cmNinjaTargetGenerator> cmNinjaTargetGenerator::New( cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target) : cmCommonTargetGenerator(target) - , MacOSXContentGenerator(nullptr) , OSXBundleGenerator(nullptr) , LocalGenerator( static_cast<cmLocalNinjaGenerator*>(target->GetLocalGenerator())) { - MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this); + for (auto const& fileConfig : target->Makefile->GetGeneratorConfigs()) { + this->Configs[fileConfig].MacOSXContentGenerator = + cm::make_unique<MacOSXContentGeneratorType>(this, fileConfig); + } } cmNinjaTargetGenerator::~cmNinjaTargetGenerator() = default; -cmGeneratedFileStream& cmNinjaTargetGenerator::GetBuildFileStream() const +cmGeneratedFileStream& cmNinjaTargetGenerator::GetImplFileStream( + const std::string& config) const +{ + return *this->GetGlobalGenerator()->GetImplFileStream(config); +} + +cmGeneratedFileStream& cmNinjaTargetGenerator::GetCommonFileStream() const { - return *this->GetGlobalGenerator()->GetBuildFileStream(); + return *this->GetGlobalGenerator()->GetCommonFileStream(); } cmGeneratedFileStream& cmNinjaTargetGenerator::GetRulesFileStream() const @@ -84,17 +92,21 @@ cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const } std::string cmNinjaTargetGenerator::LanguageCompilerRule( - const std::string& lang) const + const std::string& lang, const std::string& config) const { - return lang + "_COMPILER__" + - cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()); + return cmStrCat( + lang, "_COMPILER__", + cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), + '_', config); } std::string cmNinjaTargetGenerator::LanguagePreprocessRule( - std::string const& lang) const + std::string const& lang, const std::string& config) const { - return lang + "_PREPROCESS__" + - cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()); + return cmStrCat( + lang, "_PREPROCESS__", + cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), + '_', config); } bool cmNinjaTargetGenerator::NeedExplicitPreprocessing( @@ -117,10 +129,12 @@ bool cmNinjaTargetGenerator::CompilePreprocessedSourceWithDefines( } std::string cmNinjaTargetGenerator::LanguageDyndepRule( - const std::string& lang) const + const std::string& lang, const std::string& config) const { - return lang + "_DYNDEP__" + - cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()); + return cmStrCat( + lang, "_DYNDEP__", + cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), + '_', config); } bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const @@ -128,9 +142,11 @@ bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const return lang == "Fortran"; } -std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget() +std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget( + const std::string& config) { - return "cmake_object_order_depends_target_" + this->GetTargetName(); + return cmGlobalNinjaGenerator::OrderDependsTargetForTarget( + this->GeneratorTarget, config); } // TODO: Most of the code is picked up from @@ -138,10 +154,10 @@ std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget() // void cmMakefileTargetGenerator::WriteTargetLanguageFlags() // Refactor it. std::string cmNinjaTargetGenerator::ComputeFlagsForObject( - cmSourceFile const* source, const std::string& language) + cmSourceFile const* source, const std::string& language, + const std::string& config) { - std::string flags = this->GetFlags(language); - const std::string configName = this->LocalGenerator->GetConfigName(); + std::string flags = this->GetFlags(language, config); // Add Fortran format flags. if (language == "Fortran") { @@ -150,7 +166,7 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( // Add source file specific flags. cmGeneratorExpressionInterpreter genexInterpreter( - this->LocalGenerator, configName, this->GeneratorTarget, language); + this->LocalGenerator, config, this->GeneratorTarget, language); const std::string COMPILE_FLAGS("COMPILE_FLAGS"); if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) { @@ -166,16 +182,16 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( // Add precompile headers compile options. const std::string pchSource = - this->GeneratorTarget->GetPchSource(configName, language); + this->GeneratorTarget->GetPchSource(config, language); if (!pchSource.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { std::string pchOptions; if (source->GetFullPath() == pchSource) { - pchOptions = this->GeneratorTarget->GetPchCreateCompileOptions( - configName, language); + pchOptions = + this->GeneratorTarget->GetPchCreateCompileOptions(config, language); } else { pchOptions = - this->GeneratorTarget->GetPchUseCompileOptions(configName, language); + this->GeneratorTarget->GetPchUseCompileOptions(config, language); } this->LocalGenerator->AppendCompileOptions( @@ -186,16 +202,17 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( } void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags, - std::string const& language) + std::string const& language, + const std::string& config) { std::vector<std::string> includes; this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, - language, this->GetConfigName()); + language, config); // Add include directory flags. std::string includeFlags = this->LocalGenerator->GetIncludeFlags( includes, this->GeneratorTarget, language, language == "RC", // full include paths for RC needed by cmcldeps - false, this->GetConfigName()); + false, config); if (this->GetGlobalGenerator()->IsGCCOnWindows()) { std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/'); } @@ -205,8 +222,8 @@ void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags, bool cmNinjaTargetGenerator::NeedDepTypeMSVC(const std::string& lang) const { - std::string const& deptype = - this->GetMakefile()->GetSafeDefinition("CMAKE_NINJA_DEPTYPE_" + lang); + std::string const& deptype = this->GetMakefile()->GetSafeDefinition( + cmStrCat("CMAKE_NINJA_DEPTYPE_", lang)); if (deptype == "msvc") { return true; } @@ -232,13 +249,18 @@ bool cmNinjaTargetGenerator::NeedDepTypeMSVC(const std::string& lang) const // TODO: Refactor with // void cmMakefileTargetGenerator::WriteTargetLanguageFlags(). std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source, - const std::string& language) + const std::string& language, + const std::string& config) { std::set<std::string> defines; - const std::string config = this->LocalGenerator->GetConfigName(); cmGeneratorExpressionInterpreter genexInterpreter( this->LocalGenerator, config, this->GeneratorTarget, language); + // Seriously?? + if (this->GetGlobalGenerator()->IsMultiConfig()) { + defines.insert(cmStrCat("CMAKE_INTDIR=\"", config, '"')); + } + const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); if (const char* compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) { this->LocalGenerator->AppendDefines( @@ -253,17 +275,17 @@ std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source, genexInterpreter.Evaluate(config_compile_defs, COMPILE_DEFINITIONS)); } - std::string definesString = this->GetDefines(language); + std::string definesString = this->GetDefines(language, config); this->LocalGenerator->JoinDefines(defines, definesString, language); return definesString; } std::string cmNinjaTargetGenerator::ComputeIncludes( - cmSourceFile const* source, const std::string& language) + cmSourceFile const* source, const std::string& language, + const std::string& config) { std::vector<std::string> includes; - const std::string config = this->LocalGenerator->GetConfigName(); cmGeneratorExpressionInterpreter genexInterpreter( this->LocalGenerator, config, this->GeneratorTarget, language); @@ -277,13 +299,13 @@ std::string cmNinjaTargetGenerator::ComputeIncludes( std::string includesString = this->LocalGenerator->GetIncludeFlags( includes, this->GeneratorTarget, language, true, false, config); this->LocalGenerator->AppendFlags(includesString, - this->GetIncludes(language)); + this->GetIncludes(language, config)); return includesString; } cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps( - const std::string& linkLanguage) const + const std::string& linkLanguage, const std::string& config) const { // Static libraries never depend on other targets for linking. if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY || @@ -292,7 +314,7 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps( } cmComputeLinkInformation* cli = - this->GeneratorTarget->GetLinkInformation(this->GetConfigName()); + this->GeneratorTarget->GetLinkInformation(config); if (!cli) { return cmNinjaDeps(); } @@ -303,8 +325,7 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps( // Add a dependency on the link definitions file, if any. if (cmGeneratorTarget::ModuleDefinitionInfo const* mdi = - this->GeneratorTarget->GetModuleDefinitionInfo( - this->GetConfigName())) { + this->GeneratorTarget->GetModuleDefinitionInfo(config)) { for (cmSourceFile const* src : mdi->Sources) { result.push_back(this->ConvertToNinjaPath(src->GetFullPath())); } @@ -312,15 +333,14 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps( // Add a dependency on user-specified manifest files, if any. std::vector<cmSourceFile const*> manifest_srcs; - this->GeneratorTarget->GetManifests(manifest_srcs, this->ConfigName); + this->GeneratorTarget->GetManifests(manifest_srcs, config); for (cmSourceFile const* manifest_src : manifest_srcs) { result.push_back(this->ConvertToNinjaPath(manifest_src->GetFullPath())); } // Add user-specified dependencies. std::vector<std::string> linkDeps; - this->GeneratorTarget->GetLinkDepends(linkDeps, this->ConfigName, - linkLanguage); + this->GeneratorTarget->GetLinkDepends(linkDeps, config, linkLanguage); std::transform(linkDeps.begin(), linkDeps.end(), std::back_inserter(result), MapToNinjaPath()); @@ -334,21 +354,21 @@ std::string cmNinjaTargetGenerator::GetSourceFilePath( } std::string cmNinjaTargetGenerator::GetObjectFilePath( - cmSourceFile const* source) const + cmSourceFile const* source, const std::string& config) const { std::string path = this->LocalGenerator->GetHomeRelativeOutputPath(); if (!path.empty()) { - path += "/"; + path += '/'; } std::string const& objectName = this->GeneratorTarget->GetObjectName(source); - path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - path += "/"; - path += objectName; + path += cmStrCat( + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), + this->GetGlobalGenerator()->ConfigDirectory(config), '/', objectName); return path; } std::string cmNinjaTargetGenerator::GetPreprocessedFilePath( - cmSourceFile const* source) const + cmSourceFile const* source, const std::string& config) const { // Choose an extension to compile already-preprocessed source. std::string ppExt = source->GetExtension(); @@ -371,57 +391,57 @@ std::string cmNinjaTargetGenerator::GetPreprocessedFilePath( this->GetGlobalGenerator()->GetLanguageOutputExtension(*source); assert(objName.size() >= objExt.size()); std::string const ppName = - objName.substr(0, objName.size() - objExt.size()) + "-pp." + ppExt; + cmStrCat(objName.substr(0, objName.size() - objExt.size()), "-pp.", ppExt); std::string path = this->LocalGenerator->GetHomeRelativeOutputPath(); if (!path.empty()) { - path += "/"; + path += '/'; } - path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - path += "/"; - path += ppName; + path += + cmStrCat(this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), + this->GetGlobalGenerator()->ConfigDirectory(config), '/', ppName); return path; } std::string cmNinjaTargetGenerator::GetDyndepFilePath( - std::string const& lang) const + std::string const& lang, const std::string& config) const { std::string path = this->LocalGenerator->GetHomeRelativeOutputPath(); if (!path.empty()) { - path += "/"; + path += '/'; } - path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - path += "/"; - path += lang; - path += ".dd"; + path += cmStrCat( + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), + this->GetGlobalGenerator()->ConfigDirectory(config), '/', lang, ".dd"); return path; } std::string cmNinjaTargetGenerator::GetTargetDependInfoPath( - std::string const& lang) const + std::string const& lang, const std::string& config) const { std::string path = cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), - '/', lang, "DependInfo.json"); + this->GetGlobalGenerator()->ConfigDirectory(config), '/', lang, + "DependInfo.json"); return path; } -std::string cmNinjaTargetGenerator::GetTargetOutputDir() const +std::string cmNinjaTargetGenerator::GetTargetOutputDir( + const std::string& config) const { - std::string dir = this->GeneratorTarget->GetDirectory(this->GetConfigName()); + std::string dir = this->GeneratorTarget->GetDirectory(config); return ConvertToNinjaPath(dir); } std::string cmNinjaTargetGenerator::GetTargetFilePath( - const std::string& name) const + const std::string& name, const std::string& config) const { - std::string path = this->GetTargetOutputDir(); + std::string path = this->GetTargetOutputDir(config); if (path.empty() || path == ".") { return name; } - path += "/"; - path += name; + path += cmStrCat('/', name); return path; } @@ -430,21 +450,21 @@ std::string cmNinjaTargetGenerator::GetTargetName() const return this->GeneratorTarget->GetName(); } -bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const +bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable( + cmNinjaVars& vars, const std::string& config) const { cmMakefile* mf = this->GetMakefile(); if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") || mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID") || mf->GetDefinition("MSVC_CUDA_ARCHITECTURE_ID")) { std::string pdbPath; - std::string compilePdbPath = this->ComputeTargetCompilePDB(); + std::string compilePdbPath = this->ComputeTargetCompilePDB(config); if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE || this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY || this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY || this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) { - pdbPath = cmStrCat( - this->GeneratorTarget->GetPDBDirectory(this->GetConfigName()), '/', - this->GeneratorTarget->GetPDBName(this->GetConfigName())); + pdbPath = cmStrCat(this->GeneratorTarget->GetPDBDirectory(config), '/', + this->GeneratorTarget->GetPDBName(config)); } vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat( @@ -460,15 +480,17 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const return false; } -void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language) +void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language, + const std::string& config) { #ifdef NINJA_GEN_VERBOSE_FILES this->GetRulesFileStream() << "# Rules for language " << language << "\n\n"; #endif - this->WriteCompileRule(language); + this->WriteCompileRule(language, config); } -void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) +void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, + const std::string& config) { cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); @@ -498,7 +520,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) bool const lang_supports_response = lang != "RC"; if (lang_supports_response && this->ForceResponseFile()) { std::string const responseFlagVar = - "CMAKE_" + lang + "_RESPONSE_FILE_FLAG"; + cmStrCat("CMAKE_", lang, "_RESPONSE_FILE_FLAG"); responseFlag = this->Makefile->GetSafeDefinition(responseFlagVar); if (responseFlag.empty() && lang != "CUDA") { responseFlag = "@"; @@ -509,7 +531,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) this->GetLocalGenerator()->CreateRulePlaceholderExpander()); std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat( - ConvertToNinjaPath(this->GetTargetDependInfoPath(lang)), + ConvertToNinjaPath(this->GetTargetDependInfoPath(lang, config)), cmLocalGenerator::SHELL); std::string launcher; @@ -524,7 +546,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); if (explicitPP) { - cmNinjaRule rule(this->LanguagePreprocessRule(lang)); + cmNinjaRule rule(this->LanguagePreprocessRule(lang, config)); // Explicit preprocessing always uses a depfile. rule.DepType = ""; // no deps= for multiple outputs rule.DepFile = "$DEP_FILE"; @@ -563,7 +585,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) rule.RspFile = "$RSP_FILE"; rule.RspContent = cmStrCat(' ', ppVars.Defines, ' ', ppVars.Includes, ' ', ppFlags); - ppFlags = responseFlag + rule.RspFile; + ppFlags = cmStrCat(responseFlag, rule.RspFile); ppVars.Defines = ""; ppVars.Includes = ""; } @@ -604,7 +626,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) if (needDyndep) { // Write the rule for ninja dyndep file generation. - cmNinjaRule rule(this->LanguageDyndepRule(lang)); + cmNinjaRule rule(this->LanguageDyndepRule(lang, config)); // Command line length is almost always limited -> use response file for // dyndep rules rule.RspFile = "$out.rsp"; @@ -628,13 +650,13 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) this->GetGlobalGenerator()->AddRule(rule); } - cmNinjaRule rule(this->LanguageCompilerRule(lang)); + cmNinjaRule rule(this->LanguageCompilerRule(lang, config)); // If using a response file, move defines, includes, and flags into it. if (!responseFlag.empty()) { rule.RspFile = "$RSP_FILE"; rule.RspContent = cmStrCat(' ', vars.Defines, ' ', vars.Includes, ' ', flags); - flags = responseFlag + rule.RspFile; + flags = cmStrCat(responseFlag, rule.RspFile); vars.Defines = ""; vars.Includes = ""; } @@ -647,7 +669,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) rule.DepType = "msvc"; rule.DepFile.clear(); flags += " /showIncludes"; - } else if (mf->IsOn("CMAKE_NINJA_CMCLDEPS_" + lang)) { + } else if (mf->IsOn(cmStrCat("CMAKE_NINJA_CMCLDEPS_", lang))) { // For the MS resource compiler we need cmcldeps, but skip dependencies // for source-file try_compile cases because they are always fresh. if (!mf->GetIsSourceFileTryCompile()) { @@ -664,14 +686,14 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) } else { rule.DepType = "gcc"; rule.DepFile = "$DEP_FILE"; - const std::string flagsName = "CMAKE_DEPFILE_FLAGS_" + lang; + const std::string flagsName = cmStrCat("CMAKE_DEPFILE_FLAGS_", lang); std::string depfileFlags = mf->GetSafeDefinition(flagsName); if (!depfileFlags.empty()) { cmSystemTools::ReplaceString(depfileFlags, "<DEPFILE>", "$DEP_FILE"); cmSystemTools::ReplaceString(depfileFlags, "<OBJECT>", "$out"); cmSystemTools::ReplaceString(depfileFlags, "<CMAKE_C_COMPILER>", mf->GetDefinition("CMAKE_C_COMPILER")); - flags += " " + depfileFlags; + flags += cmStrCat(' ', depfileFlags); } } @@ -694,7 +716,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar); cmExpandList(compileCmd, compileCmds); } else { - const std::string cmdVar = "CMAKE_" + lang + "_COMPILE_OBJECT"; + const std::string cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT"); const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar); cmExpandList(compileCmd, compileCmds); } @@ -704,7 +726,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) if (!compileCmds.empty() && (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" || lang == "OBJC" || lang == "OBJCXX")) { - std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; + std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER"); const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); if (clauncher && *clauncher) { compilerLauncher = clauncher; @@ -713,13 +735,13 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) // Maybe insert an include-what-you-use runner. if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) { - std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; + std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE"); const char* iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); - std::string const tidy_prop = lang + "_CLANG_TIDY"; + std::string const tidy_prop = cmStrCat(lang, "_CLANG_TIDY"); const char* tidy = this->GeneratorTarget->GetProperty(tidy_prop); - std::string const cpplint_prop = lang + "_CPPLINT"; + std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT"); const char* cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); - std::string const cppcheck_prop = lang + "_CPPCHECK"; + std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK"); const char* cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) || (cppcheck && *cppcheck)) { @@ -727,25 +749,32 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) if (!compilerLauncher.empty()) { // In __run_co_compile case the launcher command is supplied // via --launcher=<maybe-list> and consumed - run_iwyu += " --launcher="; - run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher); + run_iwyu += + cmStrCat(" --launcher=", + this->LocalGenerator->EscapeForShell(compilerLauncher)); compilerLauncher.clear(); } if (iwyu && *iwyu) { - run_iwyu += " --iwyu="; - run_iwyu += this->GetLocalGenerator()->EscapeForShell(iwyu); + run_iwyu += cmStrCat(" --iwyu=", + this->GetLocalGenerator()->EscapeForShell(iwyu)); } if (tidy && *tidy) { run_iwyu += " --tidy="; - run_iwyu += this->GetLocalGenerator()->EscapeForShell(tidy); + const char* driverMode = this->Makefile->GetDefinition( + cmStrCat("CMAKE_", lang, "_CLANG_TIDY_DRIVER_MODE")); + if (!(driverMode && *driverMode)) { + driverMode = lang == "C" ? "gcc" : "g++"; + } + run_iwyu += this->GetLocalGenerator()->EscapeForShell( + cmStrCat(tidy, ";--extra-arg-before=--driver-mode=", driverMode)); } if (cpplint && *cpplint) { - run_iwyu += " --cpplint="; - run_iwyu += this->GetLocalGenerator()->EscapeForShell(cpplint); + run_iwyu += cmStrCat( + " --cpplint=", this->GetLocalGenerator()->EscapeForShell(cpplint)); } if (cppcheck && *cppcheck) { - run_iwyu += " --cppcheck="; - run_iwyu += this->GetLocalGenerator()->EscapeForShell(cppcheck); + run_iwyu += cmStrCat( + " --cppcheck=", this->GetLocalGenerator()->EscapeForShell(cppcheck)); } if ((tidy && *tidy) || (cpplint && *cpplint) || (cppcheck && *cppcheck)) { @@ -767,7 +796,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) i = this->LocalGenerator->EscapeForShell(i); } } - compileCmds.front().insert(0, cmJoin(args, " ") + " "); + compileCmds.front().insert(0, cmStrCat(cmJoin(args, " "), ' ')); } if (!compileCmds.empty()) { @@ -788,70 +817,75 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) this->GetGlobalGenerator()->AddRule(rule); } -void cmNinjaTargetGenerator::WriteObjectBuildStatements() +void cmNinjaTargetGenerator::WriteObjectBuildStatements( + const std::string& config, const std::string& fileConfig, + bool firstForConfig) { // Write comments. - cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream()); - this->GetBuildFileStream() + cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig)); + this->GetImplFileStream(fileConfig) << "# Object build statements for " << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) << " target " << this->GetTargetName() << "\n\n"; { std::vector<cmSourceFile const*> customCommands; - this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName); + this->GeneratorTarget->GetCustomCommands(customCommands, config); for (cmSourceFile const* sf : customCommands) { cmCustomCommand const* cc = sf->GetCustomCommand(); this->GetLocalGenerator()->AddCustomCommandTarget( cc, this->GetGeneratorTarget()); // Record the custom commands for this target. The container is used // in WriteObjectBuildStatement when called in a loop below. - this->CustomCommands.push_back(cc); + this->Configs[config].CustomCommands.push_back(cc); } } { std::vector<cmSourceFile const*> headerSources; - this->GeneratorTarget->GetHeaderSources(headerSources, this->ConfigName); + this->GeneratorTarget->GetHeaderSources(headerSources, config); this->OSXBundleGenerator->GenerateMacOSXContentStatements( - headerSources, this->MacOSXContentGenerator.get()); + headerSources, this->Configs[fileConfig].MacOSXContentGenerator.get(), + config); } { std::vector<cmSourceFile const*> extraSources; - this->GeneratorTarget->GetExtraSources(extraSources, this->ConfigName); + this->GeneratorTarget->GetExtraSources(extraSources, config); this->OSXBundleGenerator->GenerateMacOSXContentStatements( - extraSources, this->MacOSXContentGenerator.get()); + extraSources, this->Configs[fileConfig].MacOSXContentGenerator.get(), + config); } - { + if (firstForConfig) { const char* pchExtension = GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION"); std::vector<cmSourceFile const*> externalObjects; - this->GeneratorTarget->GetExternalObjects(externalObjects, - this->ConfigName); + this->GeneratorTarget->GetExternalObjects(externalObjects, config); for (cmSourceFile const* sf : externalObjects) { - const auto objectFileName = this->GetSourceFilePath(sf); + auto objectFileName = this->GetGlobalGenerator()->ExpandCFGIntDir( + this->GetSourceFilePath(sf), config); if (!cmSystemTools::StringEndsWith(objectFileName, pchExtension)) { - this->Objects.push_back(objectFileName); + this->Configs[config].Objects.push_back(objectFileName); } } } { cmNinjaBuild build("phony"); - build.Comment = "Order-only phony target for " + this->GetTargetName(); - build.Outputs.push_back(this->OrderDependsTargetForTarget()); + build.Comment = + cmStrCat("Order-only phony target for ", this->GetTargetName()); + build.Outputs.push_back(this->OrderDependsTargetForTarget(config)); cmNinjaDeps& orderOnlyDeps = build.OrderOnlyDeps; this->GetLocalGenerator()->AppendTargetDepends( - this->GeneratorTarget, orderOnlyDeps, DependOnTargetOrdering); + this->GeneratorTarget, orderOnlyDeps, config, fileConfig, + DependOnTargetOrdering); // Add order-only dependencies on other files associated with the target. - cmAppend(orderOnlyDeps, this->ExtraFiles); + cm::append(orderOnlyDeps, this->Configs[config].ExtraFiles); // Add order-only dependencies on custom command outputs. - for (cmCustomCommand const* cc : this->CustomCommands) { - cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), - this->GetLocalGenerator()); + for (cmCustomCommand const* cc : this->Configs[config].CustomCommands) { + cmCustomCommandGenerator ccg(*cc, config, this->GetLocalGenerator()); const std::vector<std::string>& ccoutputs = ccg.GetOutputs(); const std::vector<std::string>& ccbyproducts = ccg.GetByproducts(); std::transform(ccoutputs.begin(), ccoutputs.end(), @@ -877,26 +911,27 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements() orderOnlyDeps.push_back(this->ConvertToNinjaPath(tgtDir)); } - this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build); + this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), + build); } { std::vector<cmSourceFile const*> objectSources; - this->GeneratorTarget->GetObjectSources(objectSources, this->ConfigName); + this->GeneratorTarget->GetObjectSources(objectSources, config); for (cmSourceFile const* sf : objectSources) { - this->WriteObjectBuildStatement(sf); + this->WriteObjectBuildStatement(sf, config, fileConfig, firstForConfig); } } - for (auto const& langDDIFiles : this->DDIFiles) { + for (auto const& langDDIFiles : this->Configs[config].DDIFiles) { std::string const& language = langDDIFiles.first; cmNinjaDeps const& ddiFiles = langDDIFiles.second; - cmNinjaBuild build(this->LanguageDyndepRule(language)); - build.Outputs.push_back(this->GetDyndepFilePath(language)); + cmNinjaBuild build(this->LanguageDyndepRule(language, config)); + build.Outputs.push_back(this->GetDyndepFilePath(language, config)); build.ExplicitDeps = ddiFiles; - this->WriteTargetDependInfo(language); + this->WriteTargetDependInfo(language, config); // Make sure dyndep files for all our dependencies have already // been generated so that the '<LANG>Modules.json' files they @@ -907,53 +942,59 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements() // refactoring the Ninja generator to generate targets in // dependency order so that we can collect the needed information. this->GetLocalGenerator()->AppendTargetDepends( - this->GeneratorTarget, build.OrderOnlyDeps, DependOnTargetArtifact); + this->GeneratorTarget, build.OrderOnlyDeps, config, fileConfig, + DependOnTargetArtifact); - this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build); + this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), + build); } - this->GetBuildFileStream() << "\n"; + this->GetImplFileStream(fileConfig) << "\n"; - if (!this->SwiftOutputMap.empty()) { + if (!this->Configs[config].SwiftOutputMap.empty()) { std::string const mapFilePath = - this->GeneratorTarget->GetSupportDirectory() + "/output-file-map.json"; - std::string const targetSwiftDepsPath = [this]() -> std::string { + cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/', + "output-file-map.json"); + std::string const targetSwiftDepsPath = [this, config]() -> std::string { cmGeneratorTarget const* target = this->GeneratorTarget; if (const char* name = target->GetProperty("Swift_DEPENDENCIES_FILE")) { return name; } - return this->ConvertToNinjaPath(target->GetSupportDirectory() + "/" + - target->GetName() + ".swiftdeps"); + 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->SwiftOutputMap[""] = deps; + this->Configs[config].SwiftOutputMap[""] = deps; cmGeneratedFileStream output(mapFilePath); - output << this->SwiftOutputMap; + output << this->Configs[config].SwiftOutputMap; } } void cmNinjaTargetGenerator::WriteObjectBuildStatement( - cmSourceFile const* source) + cmSourceFile const* source, const std::string& config, + const std::string& fileConfig, bool firstForConfig) { std::string const language = source->GetLanguage(); std::string const sourceFileName = language == "RC" ? source->GetFullPath() : this->GetSourceFilePath(source); - std::string const objectDir = - this->ConvertToNinjaPath(this->GeneratorTarget->GetSupportDirectory()); + std::string const objectDir = this->ConvertToNinjaPath( + cmStrCat(this->GeneratorTarget->GetSupportDirectory(), + this->GetGlobalGenerator()->ConfigDirectory(config))); std::string const objectFileName = - this->ConvertToNinjaPath(this->GetObjectFilePath(source)); + this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)); std::string const objectFileDir = cmSystemTools::GetFilenamePath(objectFileName); std::string cmakeVarLang = cmStrCat("CMAKE_", language); // build response file name - std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_FLAG"; + std::string cmakeLinkVar = cmStrCat(cmakeVarLang, "_RESPONSE_FILE_FLAG"); const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar); @@ -962,11 +1003,11 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( int const commandLineLengthLimit = ((lang_supports_response && this->ForceResponseFile())) ? -1 : 0; - cmNinjaBuild objBuild(this->LanguageCompilerRule(language)); + cmNinjaBuild objBuild(this->LanguageCompilerRule(language, config)); cmNinjaVars& vars = objBuild.Variables; - vars["FLAGS"] = this->ComputeFlagsForObject(source, language); - vars["DEFINES"] = this->ComputeDefines(source, language); - vars["INCLUDES"] = this->ComputeIncludes(source, language); + vars["FLAGS"] = this->ComputeFlagsForObject(source, language, config); + vars["DEFINES"] = this->ComputeDefines(source, language, config); + vars["INCLUDES"] = this->ComputeIncludes(source, language, config); if (!this->NeedDepTypeMSVC(language)) { bool replaceExt(false); @@ -978,14 +1019,15 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( if (!replaceExt) { // use original code vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( - objectFileName + ".d", cmOutputConverter::SHELL); + cmStrCat(objectFileName, ".d"), cmOutputConverter::SHELL); } else { // Replace the original source file extension with the // depend file extension. - std::string dependFileName = - cmSystemTools::GetFilenameWithoutLastExtension(objectFileName) + ".d"; + std::string dependFileName = cmStrCat( + cmSystemTools::GetFilenameWithoutLastExtension(objectFileName), ".d"); vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( - objectFileDir + "/" + dependFileName, cmOutputConverter::SHELL); + cmStrCat(objectFileDir, '/', dependFileName), + cmOutputConverter::SHELL); } } @@ -994,11 +1036,13 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"]); objBuild.Outputs.push_back(objectFileName); - const char* pchExtension = - this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION"); - if (!cmSystemTools::StringEndsWith(objectFileName, pchExtension)) { - // Add this object to the list of object files. - this->Objects.push_back(objectFileName); + if (firstForConfig) { + const char* pchExtension = + this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION"); + if (!cmSystemTools::StringEndsWith(objectFileName, pchExtension)) { + // Add this object to the list of object files. + this->Configs[config].Objects.push_back(objectFileName); + } } objBuild.ExplicitDeps.push_back(sourceFileName); @@ -1007,13 +1051,11 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( std::vector<std::string> depList; const std::string pchSource = - this->GeneratorTarget->GetPchSource(this->GetConfigName(), language); + this->GeneratorTarget->GetPchSource(config, language); if (!pchSource.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { - depList.push_back( - this->GeneratorTarget->GetPchHeader(this->GetConfigName(), language)); + depList.push_back(this->GeneratorTarget->GetPchHeader(config, language)); if (source->GetFullPath() != pchSource) { - depList.push_back( - this->GeneratorTarget->GetPchFile(this->GetConfigName(), language)); + depList.push_back(this->GeneratorTarget->GetPchFile(config, language)); } } @@ -1034,7 +1076,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( MapToNinjaPath()); } - objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget()); + objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget(config)); // If the source file is GENERATED and does not have a custom command // (either attached to this source file or another one), assume that one of @@ -1054,13 +1096,13 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // For some cases we do an explicit preprocessor invocation. bool const explicitPP = this->NeedExplicitPreprocessing(language); if (explicitPP) { - cmNinjaBuild ppBuild(this->LanguagePreprocessRule(language)); + cmNinjaBuild ppBuild(this->LanguagePreprocessRule(language, config)); std::string const ppFileName = - this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source)); + this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source, config)); ppBuild.Outputs.push_back(ppFileName); - ppBuild.RspFile = ppFileName + ".rsp"; + ppBuild.RspFile = cmStrCat(ppFileName, ".rsp"); bool const compilePP = this->UsePreprocessedSource(language); bool const compilePPWithDefines = @@ -1089,7 +1131,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // In case compilation requires flags that are incompatible with // preprocessing, include them here. std::string const& postFlag = this->Makefile->GetSafeDefinition( - "CMAKE_" + language + "_POSTPROCESS_FLAG"); + cmStrCat("CMAKE_", language, "_POSTPROCESS_FLAG")); this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag); } @@ -1115,15 +1157,15 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags( sourceDirectory, this->GeneratorTarget, language, false, false, - this->GetConfigName()); + config); - vars["INCLUDES"] = sourceDirectoryFlag + " " + vars["INCLUDES"]; + vars["INCLUDES"] = cmStrCat(sourceDirectoryFlag, ' ', vars["INCLUDES"]); } // Explicit preprocessing always uses a depfile. ppBuild.Variables["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( - objectFileName + ".pp.d", cmOutputConverter::SHELL); + cmStrCat(objectFileName, ".pp.d"), cmOutputConverter::SHELL); if (compilePP) { // The actual compilation does not need a depfile because it // depends on the already-preprocessed source. @@ -1136,20 +1178,22 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( ppBuild.Variables["OBJ_FILE"] = objectFileName; // Tell dependency scanner where to store dyndep intermediate results. - std::string const ddiFile = objectFileName + ".ddi"; + std::string const ddiFile = cmStrCat(objectFileName, ".ddi"); ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile; ppBuild.ImplicitOuts.push_back(ddiFile); - this->DDIFiles[language].push_back(ddiFile); + if (firstForConfig) { + this->Configs[config].DDIFiles[language].push_back(ddiFile); + } } this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(), ppBuild.Variables); - this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), ppBuild, - commandLineLengthLimit); + this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), + ppBuild, commandLineLengthLimit); } if (needDyndep) { - std::string const dyndep = this->GetDyndepFilePath(language); + std::string const dyndep = this->GetDyndepFilePath(language, config); objBuild.OrderOnlyDeps.push_back(dyndep); vars["dyndep"] = dyndep; } @@ -1164,14 +1208,21 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(), vars); - this->SetMsvcTargetPdbVariable(vars); + if (!pchSource.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (source->GetFullPath() == pchSource) { + this->addPoolNinjaVariable("JOB_POOL_PRECOMPILE_HEADER", + this->GetGeneratorTarget(), vars); + } + } + + this->SetMsvcTargetPdbVariable(vars, config); - objBuild.RspFile = objectFileName + ".rsp"; + objBuild.RspFile = cmStrCat(objectFileName, ".rsp"); if (language == "Swift") { - this->EmitSwiftDependencyInfo(source); + this->EmitSwiftDependencyInfo(source, config); } else { - this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), + this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), objBuild, commandLineLengthLimit); } @@ -1182,16 +1233,18 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( std::transform(build.Outputs.begin(), build.Outputs.end(), build.Outputs.begin(), MapToNinjaPath()); build.ExplicitDeps = objBuild.Outputs; - this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), build); + this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), + build); } } -void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang) +void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang, + const std::string& config) { Json::Value tdi(Json::objectValue); tdi["language"] = lang; - tdi["compiler-id"] = - this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID"); + tdi["compiler-id"] = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_COMPILER_ID")); if (lang == "Fortran") { std::string mod_dir = this->GeneratorTarget->GetFortranModuleDirectory( @@ -1214,7 +1267,7 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang) Json::Value& tdi_include_dirs = tdi["include-dirs"] = Json::arrayValue; std::vector<std::string> includes; this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, - lang, this->GetConfigName()); + lang, config); for (std::string const& i : includes) { // Convert the include directories the same way we do for -I flags. // See upstream ninja issue 1251. @@ -1223,48 +1276,49 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang) Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] = Json::arrayValue; - for (std::string const& l : this->GetLinkedTargetDirectories()) { + for (std::string const& l : this->GetLinkedTargetDirectories(config)) { tdi_linked_target_dirs.append(l); } - std::string const tdin = this->GetTargetDependInfoPath(lang); + std::string const tdin = this->GetTargetDependInfoPath(lang, config); cmGeneratedFileStream tdif(tdin); tdif << tdi; } void cmNinjaTargetGenerator::EmitSwiftDependencyInfo( - cmSourceFile const* source) + cmSourceFile const* source, const std::string& config) { std::string const sourceFilePath = this->ConvertToNinjaPath(this->GetSourceFilePath(source)); std::string const objectFilePath = - this->ConvertToNinjaPath(this->GetObjectFilePath(source)); + this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)); std::string const swiftDepsPath = [source, objectFilePath]() -> std::string { if (const char* name = source->GetProperty("Swift_DEPENDENCIES_FILE")) { return name; } - return objectFilePath + ".swiftdeps"; + return cmStrCat(objectFilePath, ".swiftdeps"); }(); std::string const swiftDiaPath = [source, objectFilePath]() -> std::string { if (const char* name = source->GetProperty("Swift_DIAGNOSTICS_FILE")) { return name; } - return objectFilePath + ".dia"; + return cmStrCat(objectFilePath, ".dia"); }(); - std::string const makeDepsPath = [this, source]() -> std::string { + std::string const makeDepsPath = [this, source, config]() -> std::string { cmLocalNinjaGenerator const* local = this->GetLocalGenerator(); std::string const objectFileName = - this->ConvertToNinjaPath(this->GetObjectFilePath(source)); + this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)); std::string const objectFileDir = cmSystemTools::GetFilenamePath(objectFileName); if (this->Makefile->IsOn("CMAKE_Swift_DEPFLE_EXTNSION_REPLACE")) { - std::string dependFileName = - cmSystemTools::GetFilenameWithoutLastExtension(objectFileName) + ".d"; - return local->ConvertToOutputFormat(objectFileDir + "/" + dependFileName, - cmOutputConverter::SHELL); + std::string dependFileName = cmStrCat( + cmSystemTools::GetFilenameWithoutLastExtension(objectFileName), ".d"); + return local->ConvertToOutputFormat( + cmStrCat(objectFileDir, '/', dependFileName), + cmOutputConverter::SHELL); } - return local->ConvertToOutputFormat(objectFileName + ".d", + return local->ConvertToOutputFormat(cmStrCat(objectFileName, ".d"), cmOutputConverter::SHELL); }(); @@ -1275,7 +1329,7 @@ void cmNinjaTargetGenerator::EmitSwiftDependencyInfo( entry["dependencies"] = makeDepsPath; entry["swift-dependencies"] = swiftDepsPath; entry["diagnostics"] = swiftDiaPath; - SwiftOutputMap[sourceFilePath] = entry; + this->Configs[config].SwiftOutputMap[sourceFilePath] = entry; } void cmNinjaTargetGenerator::ExportObjectCompileCommand( @@ -1329,7 +1383,7 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( this->GetMakefile()->GetRequiredDefinition(cmdVar); cmExpandList(compileCmd, compileCmds); } else { - const std::string cmdVar = "CMAKE_" + language + "_COMPILE_OBJECT"; + const std::string cmdVar = cmStrCat("CMAKE_", language, "_COMPILE_OBJECT"); const std::string& compileCmd = this->GetMakefile()->GetRequiredDefinition(cmdVar); cmExpandList(compileCmd, compileCmds); @@ -1350,27 +1404,34 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName); } -void cmNinjaTargetGenerator::AdditionalCleanFiles() +void cmNinjaTargetGenerator::AdditionalCleanFiles(const std::string& config) { if (const char* prop_value = this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) { cmLocalNinjaGenerator* lg = this->LocalGenerator; std::vector<std::string> cleanFiles; - cmExpandList(cmGeneratorExpression::Evaluate( - prop_value, lg, - this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"), - this->GeneratorTarget), + cmExpandList(cmGeneratorExpression::Evaluate(prop_value, lg, config, + this->GeneratorTarget), cleanFiles); std::string const& binaryDir = lg->GetCurrentBinaryDirectory(); cmGlobalNinjaGenerator* gg = lg->GetGlobalNinjaGenerator(); for (std::string const& cleanFile : cleanFiles) { // Support relative paths gg->AddAdditionalCleanFile( - cmSystemTools::CollapseFullPath(cleanFile, binaryDir)); + cmSystemTools::CollapseFullPath(cleanFile, binaryDir), config); } } } +cmNinjaDeps cmNinjaTargetGenerator::GetObjects(const std::string& config) const +{ + auto const it = this->Configs.find(config); + if (it != this->Configs.end()) { + return it->second.Objects; + } + return {}; +} + void cmNinjaTargetGenerator::EnsureDirectoryExists( const std::string& path) const { @@ -1393,7 +1454,7 @@ void cmNinjaTargetGenerator::EnsureParentDirectoryExists( } void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()( - cmSourceFile const& source, const char* pkgloc) + cmSourceFile const& source, const char* pkgloc, const std::string& config) { // Skip OS X content when not building a Framework or Bundle. if (!this->Generator->GetGeneratorTarget()->IsBundleOnApple()) { @@ -1401,7 +1462,18 @@ void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()( } std::string macdir = - this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc); + this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc, + config); + + // Reject files that collide with files from the Ninja file's native config. + if (config != this->FileConfig) { + std::string nativeMacdir = + this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory( + pkgloc, this->FileConfig); + if (macdir == nativeMacdir) { + return; + } + } // Get the input file location. std::string input = source.GetFullPath(); @@ -1413,11 +1485,11 @@ void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()( output = this->Generator->GetGlobalGenerator()->ConvertToNinjaPath(output); // Write a build statement to copy the content into the bundle. - this->Generator->GetGlobalGenerator()->WriteMacOSXContentBuild(input, - output); + this->Generator->GetGlobalGenerator()->WriteMacOSXContentBuild( + input, output, this->FileConfig); // Add as a dependency to the target so that it gets called. - this->Generator->ExtraFiles.push_back(std::move(output)); + this->Generator->Configs[config].ExtraFiles.push_back(std::move(output)); } void cmNinjaTargetGenerator::addPoolNinjaVariable( diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 4627bcd..8678dc3 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -9,6 +9,7 @@ #include <memory> #include <set> #include <string> +#include <utility> #include <vector> #include "cm_jsoncpp_value.h" @@ -38,16 +39,17 @@ public: /// Destructor. ~cmNinjaTargetGenerator() override; - virtual void Generate() = 0; + virtual void Generate(const std::string& config) = 0; std::string GetTargetName() const; bool NeedDepTypeMSVC(const std::string& lang) const; protected: - bool SetMsvcTargetPdbVariable(cmNinjaVars&) const; + bool SetMsvcTargetPdbVariable(cmNinjaVars&, const std::string& config) const; - cmGeneratedFileStream& GetBuildFileStream() const; + cmGeneratedFileStream& GetImplFileStream(const std::string& config) const; + cmGeneratedFileStream& GetCommonFileStream() const; cmGeneratedFileStream& GetRulesFileStream() const; cmGeneratorTarget* GetGeneratorTarget() const @@ -64,15 +66,18 @@ protected: cmMakefile* GetMakefile() const { return this->Makefile; } - std::string LanguageCompilerRule(const std::string& lang) const; - std::string LanguagePreprocessRule(std::string const& lang) const; + std::string LanguageCompilerRule(const std::string& lang, + const std::string& config) const; + std::string LanguagePreprocessRule(std::string const& lang, + const std::string& config) const; bool NeedExplicitPreprocessing(std::string const& lang) const; - std::string LanguageDyndepRule(std::string const& lang) const; + std::string LanguageDyndepRule(std::string const& lang, + const std::string& config) const; bool NeedDyndep(std::string const& lang) const; bool UsePreprocessedSource(std::string const& lang) const; bool CompilePreprocessedSourceWithDefines(std::string const& lang) const; - std::string OrderDependsTargetForTarget(); + std::string OrderDependsTargetForTarget(const std::string& config); std::string ComputeOrderDependsForTarget(); @@ -82,15 +87,19 @@ protected: * by LanguageFlagsVarName(). */ std::string ComputeFlagsForObject(cmSourceFile const* source, - const std::string& language); + const std::string& language, + const std::string& config); - void AddIncludeFlags(std::string& flags, std::string const& lang) override; + void AddIncludeFlags(std::string& flags, std::string const& lang, + const std::string& config) override; std::string ComputeDefines(cmSourceFile const* source, - const std::string& language); + const std::string& language, + const std::string& config); std::string ComputeIncludes(cmSourceFile const* source, - const std::string& language); + const std::string& language, + const std::string& config); std::string ConvertToNinjaPath(const std::string& path) const { @@ -102,36 +111,51 @@ protected: } /// @return the list of link dependency for the given target @a target. - cmNinjaDeps ComputeLinkDeps(const std::string& linkLanguage) const; + cmNinjaDeps ComputeLinkDeps(const std::string& linkLanguage, + const std::string& config) const; /// @return the source file path for the given @a source. std::string GetSourceFilePath(cmSourceFile const* source) const; /// @return the object file path for the given @a source. - std::string GetObjectFilePath(cmSourceFile const* source) const; + std::string GetObjectFilePath(cmSourceFile const* source, + const std::string& config) const; /// @return the preprocessed source file path for the given @a source. - std::string GetPreprocessedFilePath(cmSourceFile const* source) const; + std::string GetPreprocessedFilePath(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 GetDyndepFilePath(std::string const& lang, + const std::string& config) const; /// @return the target dependency scanner info file path - std::string GetTargetDependInfoPath(std::string const& lang) const; + std::string GetTargetDependInfoPath(std::string const& lang, + const std::string& config) const; /// @return the file path where the target named @a name is generated. - std::string GetTargetFilePath(const std::string& name) const; + std::string GetTargetFilePath(const std::string& name, + const std::string& config) const; /// @return the output path for the target. - virtual std::string GetTargetOutputDir() const; - - void WriteLanguageRules(const std::string& language); - void WriteCompileRule(const std::string& language); - void WriteObjectBuildStatements(); - void WriteObjectBuildStatement(cmSourceFile const* source); - void WriteTargetDependInfo(std::string const& lang); - - void EmitSwiftDependencyInfo(cmSourceFile const* source); + virtual std::string GetTargetOutputDir(const std::string& config) const; + + void WriteLanguageRules(const std::string& language, + const std::string& config); + void WriteCompileRule(const std::string& language, + const std::string& config); + void WriteObjectBuildStatements(const std::string& config, + const std::string& fileConfig, + bool firstForConfig); + void WriteObjectBuildStatement(cmSourceFile const* source, + const std::string& config, + const std::string& fileConfig, + bool firstForConfig); + void WriteTargetDependInfo(std::string const& lang, + const std::string& config); + + void EmitSwiftDependencyInfo(cmSourceFile const* source, + const std::string& config); void ExportObjectCompileCommand( std::string const& language, std::string const& sourceFileName, @@ -139,9 +163,9 @@ protected: std::string const& objectFileDir, std::string const& flags, std::string const& defines, std::string const& includes); - void AdditionalCleanFiles(); + void AdditionalCleanFiles(const std::string& config); - cmNinjaDeps GetObjects() const { return this->Objects; } + cmNinjaDeps GetObjects(const std::string& config) const; void EnsureDirectoryExists(const std::string& dir) const; void EnsureParentDirectoryExists(const std::string& path) const; @@ -150,19 +174,22 @@ protected: struct MacOSXContentGeneratorType : cmOSXBundleGenerator::MacOSXContentGeneratorType { - MacOSXContentGeneratorType(cmNinjaTargetGenerator* g) + MacOSXContentGeneratorType(cmNinjaTargetGenerator* g, + std::string fileConfig) : Generator(g) + , FileConfig(std::move(fileConfig)) { } - void operator()(cmSourceFile const& source, const char* pkgloc) override; + void operator()(cmSourceFile const& source, const char* pkgloc, + const std::string& config) override; private: cmNinjaTargetGenerator* Generator; + std::string FileConfig; }; friend struct MacOSXContentGeneratorType; - std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator; // Properly initialized by sub-classes. std::unique_ptr<cmOSXBundleGenerator> OSXBundleGenerator; std::set<std::string> MacContentFolders; @@ -174,14 +201,21 @@ protected: private: cmLocalNinjaGenerator* LocalGenerator; - /// List of object files for this target. - cmNinjaDeps Objects; - // Fortran Support - std::map<std::string, cmNinjaDeps> DDIFiles; - // Swift Support - Json::Value SwiftOutputMap; - std::vector<cmCustomCommand const*> CustomCommands; - cmNinjaDeps ExtraFiles; + + struct ByConfig + { + /// List of object files for this target. + cmNinjaDeps Objects; + // Fortran Support + std::map<std::string, cmNinjaDeps> DDIFiles; + // Swift Support + Json::Value SwiftOutputMap; + std::vector<cmCustomCommand const*> CustomCommands; + cmNinjaDeps ExtraFiles; + std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator; + }; + + std::map<std::string, ByConfig> Configs; }; #endif // ! cmNinjaTargetGenerator_h diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index 5259037..a42d65d 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -15,13 +15,13 @@ #include "cmGeneratorTarget.h" #include "cmGlobalNinjaGenerator.h" #include "cmLocalNinjaGenerator.h" -#include "cmMakefile.h" #include "cmNinjaTypes.h" #include "cmOutputConverter.h" #include "cmSourceFile.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmTarget.h" cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator( cmGeneratorTarget* target) @@ -31,14 +31,18 @@ cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator( cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default; -void cmNinjaUtilityTargetGenerator::Generate() +void cmNinjaUtilityTargetGenerator::Generate(const std::string& config) { cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator(); cmLocalNinjaGenerator* lg = this->GetLocalGenerator(); cmGeneratorTarget* genTarget = this->GetGeneratorTarget(); + std::string configDir; + if (genTarget->Target->IsPerConfig()) { + configDir = gg->ConfigDirectory(config); + } std::string utilCommandName = - cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles/", + cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles", configDir, "/", this->GetTargetName(), ".util"); utilCommandName = this->ConvertToNinjaPath(utilCommandName); @@ -55,8 +59,8 @@ void cmNinjaUtilityTargetGenerator::Generate() for (std::vector<cmCustomCommand> const* cmdList : cmdLists) { for (cmCustomCommand const& ci : *cmdList) { - cmCustomCommandGenerator ccg(ci, this->GetConfigName(), lg); - lg->AppendCustomCommandDeps(ccg, deps); + cmCustomCommandGenerator ccg(ci, config, lg); + lg->AppendCustomCommandDeps(ccg, deps, config); lg->AppendCustomCommandLines(ccg, commands); std::vector<std::string> const& ccByproducts = ccg.GetByproducts(); std::transform(ccByproducts.begin(), ccByproducts.end(), @@ -69,13 +73,11 @@ void cmNinjaUtilityTargetGenerator::Generate() } { - std::string const& config = - this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"); std::vector<cmSourceFile*> sources; genTarget->GetSourceFiles(sources, config); for (cmSourceFile const* source : sources) { if (cmCustomCommand const* cc = source->GetCustomCommand()) { - cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), lg); + cmCustomCommandGenerator ccg(*cc, config, lg); lg->AddCustomCommandTarget(cc, genTarget); // Depend on all custom command outputs. @@ -89,13 +91,21 @@ void cmNinjaUtilityTargetGenerator::Generate() } } - lg->AppendTargetOutputs(genTarget, phonyBuild.Outputs); - lg->AppendTargetDepends(genTarget, deps); + std::string outputConfig; + if (genTarget->Target->IsPerConfig()) { + outputConfig = config; + } + lg->AppendTargetOutputs(genTarget, phonyBuild.Outputs, outputConfig); + if (genTarget->Target->GetType() != cmStateEnums::GLOBAL_TARGET) { + lg->AppendTargetOutputs(genTarget, gg->GetByproductsForCleanTarget(), + config); + } + lg->AppendTargetDepends(genTarget, deps, config, config); if (commands.empty()) { phonyBuild.Comment = "Utility command for " + this->GetTargetName(); phonyBuild.ExplicitDeps = std::move(deps); - gg->WriteBuild(this->GetBuildFileStream(), phonyBuild); + gg->WriteBuild(this->GetCommonFileStream(), phonyBuild); } else { std::string command = lg->BuildCommandLine(commands, "utility", this->GeneratorTarget); @@ -118,6 +128,7 @@ void cmNinjaUtilityTargetGenerator::Generate() lg->ConvertToOutputFormat(lg->GetBinaryDirectory(), cmOutputConverter::SHELL)); cmSystemTools::ReplaceString(command, "$(ARGS)", ""); + command = gg->ExpandCFGIntDir(command, config); if (command.find('$') != std::string::npos) { return; @@ -127,22 +138,32 @@ void cmNinjaUtilityTargetGenerator::Generate() gg->SeenCustomCommandOutput(util_output); } + std::string ccConfig; + if (genTarget->Target->IsPerConfig() && + genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) { + ccConfig = config; + } gg->WriteCustomCommandBuild(command, desc, "Utility command for " + this->GetTargetName(), /*depfile*/ "", /*job_pool*/ "", uses_terminal, - /*restat*/ true, util_outputs, deps); + /*restat*/ true, util_outputs, ccConfig, deps); phonyBuild.ExplicitDeps.push_back(utilCommandName); - gg->WriteBuild(this->GetBuildFileStream(), phonyBuild); + gg->WriteBuild(this->GetCommonFileStream(), phonyBuild); } // Find ADDITIONAL_CLEAN_FILES - this->AdditionalCleanFiles(); + this->AdditionalCleanFiles(config); // Add an alias for the logical target name regardless of what directory // contains it. Skip this for GLOBAL_TARGET because they are meant to // be per-directory and have one at the top-level anyway. if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) { - gg->AddTargetAlias(this->GetTargetName(), genTarget); + gg->AddTargetAlias(this->GetTargetName(), genTarget, config); + } else if (gg->IsMultiConfig() && genTarget->Target->IsPerConfig()) { + cmNinjaBuild phonyAlias("phony"); + gg->AppendTargetOutputs(genTarget, phonyAlias.Outputs, ""); + phonyAlias.ExplicitDeps = phonyBuild.Outputs; + gg->WriteBuild(this->GetImplFileStream(config), phonyAlias); } } diff --git a/Source/cmNinjaUtilityTargetGenerator.h b/Source/cmNinjaUtilityTargetGenerator.h index 01cc459..ca3f0a4 100644 --- a/Source/cmNinjaUtilityTargetGenerator.h +++ b/Source/cmNinjaUtilityTargetGenerator.h @@ -5,6 +5,8 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <string> + #include "cmNinjaTargetGenerator.h" class cmGeneratorTarget; @@ -15,7 +17,7 @@ public: cmNinjaUtilityTargetGenerator(cmGeneratorTarget* target); ~cmNinjaUtilityTargetGenerator() override; - void Generate() override; + void Generate(const std::string& config) override; }; #endif // ! cmNinjaUtilityTargetGenerator_h diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx index a6f4e51..7eea4b2 100644 --- a/Source/cmOSXBundleGenerator.cxx +++ b/Source/cmOSXBundleGenerator.cxx @@ -3,7 +3,6 @@ #include "cmOSXBundleGenerator.h" #include <cassert> -#include <utility> #include "cmGeneratorTarget.h" #include "cmLocalGenerator.h" @@ -15,12 +14,10 @@ class cmSourceFile; -cmOSXBundleGenerator::cmOSXBundleGenerator(cmGeneratorTarget* target, - std::string configName) +cmOSXBundleGenerator::cmOSXBundleGenerator(cmGeneratorTarget* target) : GT(target) , Makefile(target->Target->GetMakefile()) , LocalGenerator(target->GetLocalGenerator()) - , ConfigName(std::move(configName)) , MacContentFolders(nullptr) { if (this->MustSkip()) { @@ -34,34 +31,34 @@ bool cmOSXBundleGenerator::MustSkip() } void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, - std::string& outpath) + std::string& outpath, + const std::string& config) { if (this->MustSkip()) { return; } // Compute bundle directory names. - std::string out = - cmStrCat(outpath, '/', - this->GT->GetAppBundleDirectory(this->ConfigName, - cmGeneratorTarget::FullLevel)); + std::string out = cmStrCat( + outpath, '/', + this->GT->GetAppBundleDirectory(config, cmGeneratorTarget::FullLevel)); cmSystemTools::MakeDirectory(out); this->Makefile->AddCMakeOutputFile(out); // Configure the Info.plist file. Note that it needs the executable name // to be set. - std::string plist = - cmStrCat(outpath, '/', - this->GT->GetAppBundleDirectory(this->ConfigName, - cmGeneratorTarget::ContentLevel), - "/Info.plist"); + std::string plist = cmStrCat( + outpath, '/', + this->GT->GetAppBundleDirectory(config, cmGeneratorTarget::ContentLevel), + "/Info.plist"); this->LocalGenerator->GenerateAppleInfoPList(this->GT, targetName, plist); this->Makefile->AddCMakeOutputFile(plist); outpath = out; } -void cmOSXBundleGenerator::CreateFramework(const std::string& targetName, - const std::string& outpath) +void cmOSXBundleGenerator::CreateFramework( + const std::string& targetName, const std::string& outpath, + const std::string& config, const cmOSXBundleGenerator::SkipParts& skipParts) { if (this->MustSkip()) { return; @@ -70,28 +67,28 @@ void cmOSXBundleGenerator::CreateFramework(const std::string& targetName, assert(this->MacContentFolders); // Compute the location of the top-level foo.framework directory. - std::string contentdir = - cmStrCat(outpath, '/', - this->GT->GetFrameworkDirectory(this->ConfigName, - cmGeneratorTarget::ContentLevel), - '/'); + std::string contentdir = cmStrCat( + outpath, '/', + this->GT->GetFrameworkDirectory(config, cmGeneratorTarget::ContentLevel), + '/'); std::string newoutpath = outpath + "/" + - this->GT->GetFrameworkDirectory(this->ConfigName, - cmGeneratorTarget::FullLevel); + this->GT->GetFrameworkDirectory(config, cmGeneratorTarget::FullLevel); std::string frameworkVersion = this->GT->GetFrameworkVersion(); - // Configure the Info.plist file - std::string plist = newoutpath; - if (!this->Makefile->PlatformIsAppleEmbedded()) { - // Put the Info.plist file into the Resources directory. - this->MacContentFolders->insert("Resources"); - plist += "/Resources"; - } - plist += "/Info.plist"; std::string name = cmSystemTools::GetFilenameName(targetName); - this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name, plist); + if (!skipParts.infoPlist) { + // Configure the Info.plist file + std::string plist = newoutpath; + if (!this->Makefile->PlatformIsAppleEmbedded()) { + // Put the Info.plist file into the Resources directory. + this->MacContentFolders->insert("Resources"); + plist += "/Resources"; + } + plist += "/Info.plist"; + this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name, plist); + } // Generate Versions directory only for MacOSX frameworks if (this->Makefile->PlatformIsAppleEmbedded()) { @@ -156,27 +153,26 @@ void cmOSXBundleGenerator::CreateFramework(const std::string& targetName, } void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName, - const std::string& root) + const std::string& root, + const std::string& config) { if (this->MustSkip()) { return; } // Compute bundle directory names. - std::string out = - cmStrCat(root, '/', - this->GT->GetCFBundleDirectory(this->ConfigName, - cmGeneratorTarget::FullLevel)); + std::string out = cmStrCat( + root, '/', + this->GT->GetCFBundleDirectory(config, cmGeneratorTarget::FullLevel)); cmSystemTools::MakeDirectory(out); this->Makefile->AddCMakeOutputFile(out); // Configure the Info.plist file. Note that it needs the executable name // to be set. - std::string plist = - cmStrCat(root, '/', - this->GT->GetCFBundleDirectory(this->ConfigName, - cmGeneratorTarget::ContentLevel), - "/Info.plist"); + std::string plist = cmStrCat( + root, '/', + this->GT->GetCFBundleDirectory(config, cmGeneratorTarget::ContentLevel), + "/Info.plist"); std::string name = cmSystemTools::GetFilenameName(targetName); this->LocalGenerator->GenerateAppleInfoPList(this->GT, name, plist); this->Makefile->AddCMakeOutputFile(plist); @@ -184,7 +180,7 @@ void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName, void cmOSXBundleGenerator::GenerateMacOSXContentStatements( std::vector<cmSourceFile const*> const& sources, - MacOSXContentGeneratorType* generator) + MacOSXContentGeneratorType* generator, const std::string& config) { if (this->MustSkip()) { return; @@ -194,20 +190,19 @@ void cmOSXBundleGenerator::GenerateMacOSXContentStatements( cmGeneratorTarget::SourceFileFlags tsFlags = this->GT->GetTargetSourceFileFlags(source); if (tsFlags.Type != cmGeneratorTarget::SourceFileTypeNormal) { - (*generator)(*source, tsFlags.MacFolder); + (*generator)(*source, tsFlags.MacFolder, config); } } } std::string cmOSXBundleGenerator::InitMacOSXContentDirectory( - const char* pkgloc) + const char* pkgloc, const std::string& config) { // Construct the full path to the content subdirectory. - std::string macdir = - cmStrCat(this->GT->GetMacContentDirectory( - this->ConfigName, cmStateEnums::RuntimeBinaryArtifact), - '/', pkgloc); + std::string macdir = cmStrCat(this->GT->GetMacContentDirectory( + config, cmStateEnums::RuntimeBinaryArtifact), + '/', pkgloc); cmSystemTools::MakeDirectory(macdir); // Record use of this content location. Only the first level diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h index 3dea6cc..5bf1d98 100644 --- a/Source/cmOSXBundleGenerator.h +++ b/Source/cmOSXBundleGenerator.h @@ -17,29 +17,43 @@ class cmSourceFile; class cmOSXBundleGenerator { public: - cmOSXBundleGenerator(cmGeneratorTarget* target, std::string configName); + cmOSXBundleGenerator(cmGeneratorTarget* target); + + struct SkipParts + { + SkipParts() + : infoPlist(false) + { + } + bool infoPlist; // NOLINT(modernize-use-default-member-init) + }; // create an app bundle at a given root, and return // the directory within the bundle that contains the executable - void CreateAppBundle(const std::string& targetName, std::string& root); + void CreateAppBundle(const std::string& targetName, std::string& root, + const std::string& config); // create a framework at a given root - void CreateFramework(const std::string& targetName, const std::string& root); + void CreateFramework(const std::string& targetName, const std::string& root, + const std::string& config, + const SkipParts& skipParts = SkipParts()); // create a cf bundle at a given root - void CreateCFBundle(const std::string& targetName, const std::string& root); + void CreateCFBundle(const std::string& targetName, const std::string& root, + const std::string& config); struct MacOSXContentGeneratorType { virtual ~MacOSXContentGeneratorType() = default; - virtual void operator()(cmSourceFile const& source, - const char* pkgloc) = 0; + virtual void operator()(cmSourceFile const& source, const char* pkgloc, + const std::string& config) = 0; }; void GenerateMacOSXContentStatements( std::vector<cmSourceFile const*> const& sources, - MacOSXContentGeneratorType* generator); - std::string InitMacOSXContentDirectory(const char* pkgloc); + MacOSXContentGeneratorType* generator, const std::string& config); + std::string InitMacOSXContentDirectory(const char* pkgloc, + const std::string& config); void SetMacContentFolders(std::set<std::string>* macContentFolders) { @@ -53,7 +67,6 @@ private: cmGeneratorTarget* GT; cmMakefile* Makefile; cmLocalGenerator* LocalGenerator; - std::string ConfigName; std::set<std::string>* MacContentFolders; }; diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx index 073222c..0369af0 100644 --- a/Source/cmOrderDirectories.cxx +++ b/Source/cmOrderDirectories.cxx @@ -8,7 +8,9 @@ #include <sstream> #include <vector> -#include "cmAlgorithms.h" +#include <cm/memory> +#include <cmext/algorithm> + #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmMessageType.h" @@ -248,11 +250,7 @@ cmOrderDirectories::cmOrderDirectories(cmGlobalGenerator* gg, this->Computed = false; } -cmOrderDirectories::~cmOrderDirectories() -{ - cmDeleteAll(this->ConstraintEntries); - cmDeleteAll(this->ImplicitDirEntries); -} +cmOrderDirectories::~cmOrderDirectories() = default; std::vector<std::string> const& cmOrderDirectories::GetOrderedDirectories() { @@ -286,14 +284,16 @@ void cmOrderDirectories::AddRuntimeLibrary(std::string const& fullPath, if (this->IsImplicitDirectory(dir)) { this->ImplicitDirEntries.push_back( - new cmOrderDirectoriesConstraintSOName(this, fullPath, soname)); + cm::make_unique<cmOrderDirectoriesConstraintSOName>(this, fullPath, + soname)); return; } } // Construct the runtime information entry for this library. this->ConstraintEntries.push_back( - new cmOrderDirectoriesConstraintSOName(this, fullPath, soname)); + cm::make_unique<cmOrderDirectoriesConstraintSOName>(this, fullPath, + soname)); } else { // This can happen if the same library is linked multiple times. // In that case the runtime information check need be done only @@ -314,27 +314,28 @@ void cmOrderDirectories::AddLinkLibrary(std::string const& fullPath) std::string dir = cmSystemTools::GetFilenamePath(fullPath); if (this->IsImplicitDirectory(dir)) { this->ImplicitDirEntries.push_back( - new cmOrderDirectoriesConstraintLibrary(this, fullPath)); + cm::make_unique<cmOrderDirectoriesConstraintLibrary>(this, + fullPath)); return; } } // Construct the link library entry. this->ConstraintEntries.push_back( - new cmOrderDirectoriesConstraintLibrary(this, fullPath)); + cm::make_unique<cmOrderDirectoriesConstraintLibrary>(this, fullPath)); } } void cmOrderDirectories::AddUserDirectories( std::vector<std::string> const& extra) { - cmAppend(this->UserDirectories, extra); + cm::append(this->UserDirectories, extra); } void cmOrderDirectories::AddLanguageDirectories( std::vector<std::string> const& dirs) { - cmAppend(this->LanguageDirectories, dirs); + cm::append(this->LanguageDirectories, dirs); } void cmOrderDirectories::SetImplicitDirectories( @@ -369,7 +370,7 @@ void cmOrderDirectories::CollectOriginalDirectories() this->AddOriginalDirectories(this->UserDirectories); // Add directories containing constraints. - for (cmOrderDirectoriesConstraint* entry : this->ConstraintEntries) { + for (const auto& entry : this->ConstraintEntries) { entry->AddDirectory(); } @@ -454,7 +455,7 @@ void cmOrderDirectories::FindImplicitConflicts() // Check for items in implicit link directories that have conflicts // in the explicit directories. std::ostringstream conflicts; - for (cmOrderDirectoriesConstraint* entry : this->ImplicitDirEntries) { + for (const auto& entry : this->ImplicitDirEntries) { entry->FindImplicitConflicts(conflicts); } diff --git a/Source/cmOrderDirectories.h b/Source/cmOrderDirectories.h index 23c5145..8ce53e0 100644 --- a/Source/cmOrderDirectories.h +++ b/Source/cmOrderDirectories.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <map> +#include <memory> #include <set> #include <string> #include <utility> @@ -46,8 +47,9 @@ private: std::vector<std::string> OrderedDirectories; - std::vector<cmOrderDirectoriesConstraint*> ConstraintEntries; - std::vector<cmOrderDirectoriesConstraint*> ImplicitDirEntries; + std::vector<std::unique_ptr<cmOrderDirectoriesConstraint>> ConstraintEntries; + std::vector<std::unique_ptr<cmOrderDirectoriesConstraint>> + ImplicitDirEntries; std::vector<std::string> UserDirectories; std::vector<std::string> LanguageDirectories; cmsys::RegularExpression RemoveLibraryExtension; diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index e602a6d..1c6fad1 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -43,9 +43,10 @@ std::string cmOutputConverter::ConvertToOutputFormat(cm::string_view source, { std::string result(source); // Convert it to an output path. - if (output == SHELL || output == WATCOMQUOTE) { + if (output == SHELL || output == WATCOMQUOTE || output == NINJAMULTI) { result = this->ConvertDirectorySeparatorsForShell(source); - result = this->EscapeForShell(result, true, false, output == WATCOMQUOTE); + result = this->EscapeForShell(result, true, false, output == WATCOMQUOTE, + output == NINJAMULTI); } else if (output == RESPONSE) { result = this->EscapeForShell(result, false, false, false); } @@ -79,9 +80,9 @@ static bool cmOutputConverterIsShellOperator(cm::string_view str) return (shellOperators.count(str) != 0); } -std::string cmOutputConverter::EscapeForShell(cm::string_view str, - bool makeVars, bool forEcho, - bool useWatcomQuote) const +std::string cmOutputConverter::EscapeForShell( + cm::string_view str, bool makeVars, bool forEcho, bool useWatcomQuote, + bool unescapeNinjaConfiguration) const { // Do not escape shell operators. if (cmOutputConverterIsShellOperator(str)) { @@ -95,6 +96,9 @@ std::string cmOutputConverter::EscapeForShell(cm::string_view str, } else if (!this->LinkScriptShell) { flags |= Shell_Flag_Make; } + if (unescapeNinjaConfiguration) { + flags |= Shell_Flag_UnescapeNinjaConfiguration; + } if (makeVars) { flags |= Shell_Flag_AllowMakeVariables; } @@ -511,5 +515,14 @@ std::string cmOutputConverter::Shell__GetArgument(cm::string_view in, } } + if (flags & Shell_Flag_UnescapeNinjaConfiguration) { + std::string ninjaConfigReplace; + if (flags & Shell_Flag_IsUnix) { + ninjaConfigReplace += '\\'; + } + ninjaConfigReplace += "$${CONFIGURATION}"; + cmSystemTools::ReplaceString(out, ninjaConfigReplace, "${CONFIGURATION}"); + } + return out; } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 349a069..6583ab5 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -22,6 +22,7 @@ public: { SHELL, WATCOMQUOTE, + NINJAMULTI, RESPONSE }; std::string ConvertToOutputFormat(cm::string_view source, @@ -70,12 +71,14 @@ public: /** The target shell quoting uses extra single Quotes for Watcom tools. */ Shell_Flag_WatcomQuote = (1 << 7), - Shell_Flag_IsUnix = (1 << 8) + Shell_Flag_IsUnix = (1 << 8), + + Shell_Flag_UnescapeNinjaConfiguration = (1 << 9), }; std::string EscapeForShell(cm::string_view str, bool makeVars = false, - bool forEcho = false, - bool useWatcomQuote = false) const; + bool forEcho = false, bool useWatcomQuote = false, + bool unescapeNinjaConfiguration = false) const; static std::string EscapeForCMake(cm::string_view str); diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx index e093be0..147f97f 100644 --- a/Source/cmOutputRequiredFilesCommand.cxx +++ b/Source/cmOutputRequiredFilesCommand.cxx @@ -7,10 +7,11 @@ #include <set> #include <utility> +#include <cm/memory> + #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" #include "cmMakefile.h" @@ -94,7 +95,7 @@ public: /** * Destructor. */ - ~cmLBDepend() { cmDeleteAll(this->DependInformationMap); } + ~cmLBDepend() = default; cmLBDepend(const cmLBDepend&) = delete; cmLBDepend& operator=(const cmLBDepend&) = delete; @@ -152,9 +153,9 @@ public: * Generate dependencies for the file given. Returns a pointer to * the cmDependInformation object for the file. */ - const cmDependInformation* FindDependencies(const char* file) + const cmDependInformation* FindDependencies(const std::string& file) { - cmDependInformation* info = this->GetDependInformation(file, nullptr); + cmDependInformation* info = this->GetDependInformation(file, ""); this->GenerateDependInformation(info); return info; } @@ -203,7 +204,7 @@ protected: } // Add this file and all its dependencies. - this->AddDependency(info, includeFile.c_str()); + this->AddDependency(info, includeFile); /// add the cxx file if it exists std::string cxxFile = includeFile; std::string::size_type pos = cxxFile.rfind('.'); @@ -254,7 +255,7 @@ protected: } } if (found) { - this->AddDependency(info, cxxFile.c_str()); + this->AddDependency(info, cxxFile); } } } @@ -264,10 +265,10 @@ protected: /** * Add a dependency. Possibly walk it for more dependencies. */ - void AddDependency(cmDependInformation* info, const char* file) + void AddDependency(cmDependInformation* info, const std::string& file) { cmDependInformation* dependInfo = - this->GetDependInformation(file, info->PathOnly.c_str()); + this->GetDependInformation(file, info->PathOnly); this->GenerateDependInformation(dependInfo); info->AddDependencies(dependInfo); } @@ -313,7 +314,7 @@ protected: // Dependency hints have been given. Use them to begin the // recursion. for (std::string const& file : cFile.GetDepends()) { - this->AddDependency(info, file.c_str()); + this->AddDependency(info, file); } // Found dependency information. We are done. @@ -361,8 +362,8 @@ protected: * Get an instance of cmDependInformation corresponding to the given file * name. */ - cmDependInformation* GetDependInformation(const char* file, - const char* extraPath) + cmDependInformation* GetDependInformation(const std::string& file, + const std::string& extraPath) { // Get the full path for the file so that lookup is unambiguous. std::string fullPath = this->FullPath(file, extraPath); @@ -371,15 +372,16 @@ protected: auto result = this->DependInformationMap.find(fullPath); if (result != this->DependInformationMap.end()) { // Found an instance, return it. - return result->second; + return result->second.get(); } // Didn't find an instance. Create a new one and save it. - cmDependInformation* info = new cmDependInformation; + auto info = cm::make_unique<cmDependInformation>(); + auto ptr = info.get(); info->FullPath = fullPath; info->PathOnly = cmSystemTools::GetFilenamePath(fullPath); info->IncludeName = file; - this->DependInformationMap[fullPath] = info; - return info; + this->DependInformationMap[fullPath] = std::move(info); + return ptr; } /** @@ -387,14 +389,9 @@ protected: * This uses the include directories. * TODO: Cache path conversions to reduce FileExists calls. */ - std::string FullPath(const char* fname, const char* extraPath) + std::string FullPath(const std::string& fname, const std::string& extraPath) { - DirectoryToFileToPathMapType::iterator m; - if (extraPath) { - m = this->DirectoryToFileToPathMap.find(extraPath); - } else { - m = this->DirectoryToFileToPathMap.find(""); - } + auto m = this->DirectoryToFileToPathMap.find(extraPath); if (m != this->DirectoryToFileToPathMap.end()) { FileToPathMapType& map = m->second; @@ -406,7 +403,7 @@ protected: if (cmSystemTools::FileExists(fname, true)) { std::string fp = cmSystemTools::CollapseFullPath(fname); - this->DirectoryToFileToPathMap[extraPath ? extraPath : ""][fname] = fp; + this->DirectoryToFileToPathMap[extraPath][fname] = fp; return fp; } @@ -418,12 +415,12 @@ protected: if (cmSystemTools::FileExists(path, true) && !cmSystemTools::FileIsDirectory(path)) { std::string fp = cmSystemTools::CollapseFullPath(path); - this->DirectoryToFileToPathMap[extraPath ? extraPath : ""][fname] = fp; + this->DirectoryToFileToPathMap[extraPath][fname] = fp; return fp; } } - if (extraPath) { + if (!extraPath.empty()) { std::string path = extraPath; if (!path.empty() && path.back() != '/') { path = path + "/"; @@ -438,7 +435,7 @@ protected: } // Couldn't find the file. - return std::string(fname); + return fname; } cmMakefile* Makefile; @@ -449,7 +446,8 @@ protected: using FileToPathMapType = std::map<std::string, std::string>; using DirectoryToFileToPathMapType = std::map<std::string, FileToPathMapType>; - using DependInformationMapType = std::map<std::string, cmDependInformation*>; + using DependInformationMapType = + std::map<std::string, std::unique_ptr<cmDependInformation>>; DependInformationMapType DependInformationMap; DirectoryToFileToPathMapType DirectoryToFileToPathMap; }; @@ -476,7 +474,7 @@ bool cmOutputRequiredFilesCommand(std::vector<std::string> const& args, md.SetMakefile(&status.GetMakefile()); md.AddSearchPath(status.GetMakefile().GetCurrentSourceDirectory()); // find the depends for a file - const cmDependInformation* info = md.FindDependencies(file.c_str()); + const cmDependInformation* info = md.FindDependencies(file); if (info) { // write them out FILE* fout = cmsys::SystemTools::Fopen(outputFile, "w"); diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 92c80bb..1366ff0 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -290,7 +290,22 @@ class cmMakefile; SELECT(POLICY, CMP0097, \ "ExternalProject_Add with GIT_SUBMODULES \"\" initializes no " \ "submodules.", \ - 3, 16, 0, cmPolicies::WARN) + 3, 16, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0098, \ + "FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing.", 3, \ + 17, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0099, \ + "Link properties are transitive over private dependency on static " \ + "libraries.", \ + 3, 17, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0100, "Let AUTOMOC and AUTOUIC process .hh files.", 3, \ + 17, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0101, \ + "target_compile_options honors BEFORE keyword in all scopes.", 3, \ + 17, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0102, \ + "mark_as_advanced() does nothing if a cache entry does not exist.", \ + 3, 17, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ @@ -319,7 +334,8 @@ class cmMakefile; F(CMP0076) \ F(CMP0081) \ F(CMP0083) \ - F(CMP0095) + F(CMP0095) \ + F(CMP0099) /** \class cmPolicies * \brief Handles changes in CMake behavior and policies diff --git a/Source/cmProcessOutput.cxx b/Source/cmProcessOutput.cxx index e80ea5c..0fb4ff7 100644 --- a/Source/cmProcessOutput.cxx +++ b/Source/cmProcessOutput.cxx @@ -4,7 +4,10 @@ #include "cmProcessOutput.h" #if defined(_WIN32) +# include <cm/memory> + # include <windows.h> + unsigned int cmProcessOutput::defaultCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE; #endif @@ -143,9 +146,9 @@ bool cmProcessOutput::DoDecodeText(std::string raw, std::string& decoded, bool success = false; const int wlength = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), NULL, 0); - wchar_t* wdata = new wchar_t[wlength]; - int r = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), wdata, - wlength); + auto wdata = cm::make_unique<wchar_t[]>(wlength); + int r = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), + wdata.get(), wlength); if (r > 0) { if (lastChar) { *lastChar = 0; @@ -154,18 +157,16 @@ bool cmProcessOutput::DoDecodeText(std::string raw, std::string& decoded, *lastChar = wdata[wlength - 1]; } } - int length = WideCharToMultiByte(defaultCodepage, 0, wdata, wlength, NULL, - 0, NULL, NULL); - char* data = new char[length]; - r = WideCharToMultiByte(defaultCodepage, 0, wdata, wlength, data, length, - NULL, NULL); + int length = WideCharToMultiByte(defaultCodepage, 0, wdata.get(), wlength, + NULL, 0, NULL, NULL); + auto data = cm::make_unique<char[]>(length); + r = WideCharToMultiByte(defaultCodepage, 0, wdata.get(), wlength, + data.get(), length, NULL, NULL); if (r > 0) { - decoded = std::string(data, length); + decoded = std::string(data.get(), length); success = true; } - delete[] data; } - delete[] wdata; return success; } #endif diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index 7bb5209..2ec66d9 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -39,13 +39,18 @@ bool cmProjectCommand(std::vector<std::string> const& args, std::string const& projectName = args[0]; + if (!IncludeByVariable(status, + "CMAKE_PROJECT_" + projectName + "_INCLUDE_BEFORE")) { + return false; + } + mf.SetProjectName(projectName); mf.AddCacheDefinition(projectName + "_BINARY_DIR", - mf.GetCurrentBinaryDirectory().c_str(), + mf.GetCurrentBinaryDirectory(), "Value Computed by CMake", cmStateEnums::STATIC); mf.AddCacheDefinition(projectName + "_SOURCE_DIR", - mf.GetCurrentSourceDirectory().c_str(), + mf.GetCurrentSourceDirectory(), "Value Computed by CMake", cmStateEnums::STATIC); mf.AddDefinition("PROJECT_BINARY_DIR", mf.GetCurrentBinaryDirectory()); @@ -61,7 +66,7 @@ bool cmProjectCommand(std::vector<std::string> const& args, // will work. if (!mf.GetDefinition("CMAKE_PROJECT_NAME") || mf.IsRootMakefile()) { mf.AddDefinition("CMAKE_PROJECT_NAME", projectName); - mf.AddCacheDefinition("CMAKE_PROJECT_NAME", projectName.c_str(), + mf.AddCacheDefinition("CMAKE_PROJECT_NAME", projectName, "Value Computed by CMake", cmStateEnums::STATIC); } @@ -374,7 +379,7 @@ static void TopLevelCMakeVarCondSet(cmMakefile& mf, std::string const& name, // CMakeLists.txt file, then go with the last one. if (!mf.GetDefinition(name) || mf.IsRootMakefile()) { mf.AddDefinition(name, value); - mf.AddCacheDefinition(name, value.c_str(), "Value Computed by CMake", + mf.AddCacheDefinition(name, value, "Value Computed by CMake", cmStateEnums::STATIC); } } diff --git a/Source/cmPropertyMap.cxx b/Source/cmPropertyMap.cxx index a3d4946..d4b3552 100644 --- a/Source/cmPropertyMap.cxx +++ b/Source/cmPropertyMap.cxx @@ -20,11 +20,11 @@ void cmPropertyMap::SetProperty(const std::string& name, const char* value) Map_[name] = value; } -void cmPropertyMap::AppendProperty(const std::string& name, const char* value, - bool asString) +void cmPropertyMap::AppendProperty(const std::string& name, + const std::string& value, bool asString) { // Skip if nothing to append. - if (!value || !*value) { + if (value.empty()) { return; } diff --git a/Source/cmPropertyMap.h b/Source/cmPropertyMap.h index 9aed349..bea4372 100644 --- a/Source/cmPropertyMap.h +++ b/Source/cmPropertyMap.h @@ -27,7 +27,7 @@ public: void SetProperty(const std::string& name, const char* value); //! Append to the property value - void AppendProperty(const std::string& name, const char* value, + void AppendProperty(const std::string& name, const std::string& value, bool asString = false); //! Get the property value diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index eb7c900..d5891c4 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -8,6 +8,8 @@ #include <sstream> #include <utility> +#include <cmext/algorithm> + #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" @@ -67,7 +69,7 @@ void MergeOptions(std::vector<std::string>& baseOpts, } } // Append options - cmAppend(baseOpts, extraOpts); + cm::append(baseOpts, extraOpts); } // - Class definitions @@ -328,7 +330,7 @@ bool cmQtAutoGen::RccLister::list(std::string const& qrcFile, { std::vector<std::string> cmd; cmd.emplace_back(this->RccExcutable_); - cmAppend(cmd, this->ListOptions_); + cm::append(cmd, this->ListOptions_); cmd.emplace_back(cmSystemTools::GetFilenameName(qrcFile)); // Log command diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx index ef6b886..7a6cb42 100644 --- a/Source/cmQtAutoGenGlobalInitializer.cxx +++ b/Source/cmQtAutoGenGlobalInitializer.cxx @@ -7,7 +7,6 @@ #include <cm/memory> #include "cmCustomCommandLines.h" -#include "cmCustomCommandTypes.h" #include "cmDuration.h" #include "cmGeneratorTarget.h" #include "cmLocalGenerator.h" @@ -41,9 +40,9 @@ cmQtAutoGenGlobalInitializer::Keywords::Keywords() } cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( - std::vector<cmLocalGenerator*> const& localGenerators) + std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators) { - for (cmLocalGenerator* localGen : localGenerators) { + for (const auto& localGen : localGenerators) { // Detect global autogen and autorcc target names bool globalAutoGenTarget = false; bool globalAutoRccTarget = false; @@ -56,7 +55,7 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( if (targetName.empty()) { targetName = "autogen"; } - GlobalAutoGenTargets_.emplace(localGen, std::move(targetName)); + GlobalAutoGenTargets_.emplace(localGen.get(), std::move(targetName)); globalAutoGenTarget = true; } @@ -67,13 +66,13 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( if (targetName.empty()) { targetName = "autorcc"; } - GlobalAutoRccTargets_.emplace(localGen, std::move(targetName)); + GlobalAutoRccTargets_.emplace(localGen.get(), std::move(targetName)); globalAutoRccTarget = true; } } // Find targets that require AUTOMOC/UIC/RCC processing - for (cmGeneratorTarget* target : localGen->GetGeneratorTargets()) { + for (const auto& target : localGen->GetGeneratorTargets()) { // Process only certain target types switch (target->GetType()) { case cmStateEnums::EXECUTABLE: @@ -104,7 +103,7 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( target->GetSafeProperty(kw().AUTORCC_EXECUTABLE); // We support Qt4, Qt5 and Qt6 - auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target); + auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target.get()); bool const validQt = (qtVersion.first.Major == 4) || (qtVersion.first.Major == 5) || (qtVersion.first.Major == 6); @@ -135,8 +134,8 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( if (mocIsValid || uicIsValid || rccIsValid) { // Create autogen target initializer Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>( - this, target, qtVersion.first, mocIsValid, uicIsValid, rccIsValid, - globalAutoGenTarget, globalAutoRccTarget)); + this, target.get(), qtVersion.first, mocIsValid, uicIsValid, + rccIsValid, globalAutoGenTarget, globalAutoRccTarget)); } } } @@ -154,13 +153,14 @@ void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget( cmMakefile* makefile = localGen->GetMakefile(); // Create utility target - cmTarget* target = makefile->AddUtilityCommand( - name, cmCommandOrigin::Generator, true, - makefile->GetHomeOutputDirectory().c_str() /*work dir*/, - std::vector<std::string>() /*output*/, - std::vector<std::string>() /*depends*/, cmCustomCommandLines(), false, - comment.c_str()); - localGen->AddGeneratorTarget(new cmGeneratorTarget(target, localGen)); + std::vector<std::string> no_byproducts; + std::vector<std::string> no_depends; + cmCustomCommandLines no_commands; + cmTarget* target = localGen->AddUtilityCommand( + name, true, makefile->GetHomeOutputDirectory().c_str(), no_byproducts, + no_depends, no_commands, false, comment.c_str()); + localGen->AddGeneratorTarget( + cm::make_unique<cmGeneratorTarget>(target, localGen)); // Set FOLDER property in the target { @@ -180,7 +180,7 @@ void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen( if (it != GlobalAutoGenTargets_.end()) { cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second); if (target != nullptr) { - target->Target->AddUtility(targetName, localGen->GetMakefile()); + target->Target->AddUtility(targetName, false, localGen->GetMakefile()); } } } @@ -192,7 +192,7 @@ void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc( if (it != GlobalAutoRccTargets_.end()) { cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second); if (target != nullptr) { - target->Target->AddUtility(targetName, localGen->GetMakefile()); + target->Target->AddUtility(targetName, false, localGen->GetMakefile()); } } } diff --git a/Source/cmQtAutoGenGlobalInitializer.h b/Source/cmQtAutoGenGlobalInitializer.h index 806725a..2f6e581 100644 --- a/Source/cmQtAutoGenGlobalInitializer.h +++ b/Source/cmQtAutoGenGlobalInitializer.h @@ -48,7 +48,7 @@ public: public: cmQtAutoGenGlobalInitializer( - std::vector<cmLocalGenerator*> const& localGenerators); + std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators); ~cmQtAutoGenGlobalInitializer(); Keywords const& kw() const { return Keywords_; }; diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 5eb04f7..629367d 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -25,7 +25,6 @@ #include "cmAlgorithms.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" -#include "cmCustomCommandTypes.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" @@ -355,24 +354,38 @@ bool cmQtAutoGenInitializer::InitCustomTargets() } } - // Check status of policy CMP0071 - { - cmPolicies::PolicyStatus const CMP0071_status = - this->Makefile->GetPolicyStatus(cmPolicies::CMP0071); - switch (CMP0071_status) { - case cmPolicies::WARN: - this->CMP0071Warn = true; - CM_FALLTHROUGH; - case cmPolicies::OLD: - // Ignore GENERATED file - break; - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::NEW: - // Process GENERATED file - this->CMP0071Accept = true; - break; - } + // Check status of policy CMP0071 regarding handling of GENERATED files + switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0071)) { + case cmPolicies::WARN: + // Ignore GENERATED files but warn + this->CMP0071Warn = true; + CM_FALLTHROUGH; + case cmPolicies::OLD: + // Ignore GENERATED files + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // Process GENERATED files + this->CMP0071Accept = true; + break; + } + + // Check status of policy CMP0100 regarding handling of .hh headers + switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0100)) { + case cmPolicies::WARN: + // Ignore but .hh files but warn + this->CMP0100Warn = true; + CM_FALLTHROUGH; + case cmPolicies::OLD: + // Ignore .hh files + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // Process .hh file + this->CMP0100Accept = true; + break; } // Common directories @@ -734,15 +747,26 @@ bool cmQtAutoGenInitializer::InitScanFiles() return muf; }; - auto addMUFile = [&](MUFileHandle&& muf, bool isHeader) { + auto addMUHeader = [this](MUFileHandle&& muf, cm::string_view extension) { + cmSourceFile* sf = muf->SF; + const bool muIt = (muf->MocIt || muf->UicIt); + if (this->CMP0100Accept || (extension != "hh")) { + // Accept + if (muIt && muf->Generated) { + this->AutogenTarget.FilesGenerated.emplace_back(muf.get()); + } + this->AutogenTarget.Headers.emplace(sf, std::move(muf)); + } else if (muIt && this->CMP0100Warn) { + // Store file for warning message + this->AutogenTarget.CMP0100HeadersWarn.push_back(sf); + } + }; + + auto addMUSource = [this](MUFileHandle&& muf) { if ((muf->MocIt || muf->UicIt) && muf->Generated) { this->AutogenTarget.FilesGenerated.emplace_back(muf.get()); } - if (isHeader) { - this->AutogenTarget.Headers.emplace(muf->SF, std::move(muf)); - } else { - this->AutogenTarget.Sources.emplace(muf->SF, std::move(muf)); - } + this->AutogenTarget.Sources.emplace(muf->SF, std::move(muf)); }; // Scan through target files @@ -764,11 +788,10 @@ bool cmQtAutoGenInitializer::InitScanFiles() // Register files that will be scanned by moc or uic if (this->MocOrUicEnabled()) { - // FIXME: Add a policy to include .hh files. - if (cm->IsHeaderExtension(extLower) && extLower != "hh") { - addMUFile(makeMUFile(sf, fullPath, true), true); + if (cm->IsHeaderExtension(extLower)) { + addMUHeader(makeMUFile(sf, fullPath, true), extLower); } else if (cm->IsSourceExtension(extLower)) { - addMUFile(makeMUFile(sf, fullPath, true), false); + addMUSource(makeMUFile(sf, fullPath, true)); } } @@ -802,8 +825,6 @@ bool cmQtAutoGenInitializer::InitScanFiles() // For source files find additional headers and private headers if (this->MocOrUicEnabled()) { - std::vector<MUFileHandle> extraHeaders; - extraHeaders.reserve(this->AutogenTarget.Sources.size() * 2); // Header search suffixes and extensions static std::initializer_list<cm::string_view> const suffixes{ "", "_p" }; auto const& exts = cm->GetHeaderExtensions(); @@ -848,16 +869,12 @@ bool cmQtAutoGenInitializer::InitScanFiles() if (!muf.UicIt) { eMuf->UicIt = false; } - extraHeaders.emplace_back(std::move(eMuf)); + addMUHeader(std::move(eMuf), ext); } } } } } - // Move generated files to main headers list - for (auto& eMuf : extraHeaders) { - addMUFile(std::move(eMuf), true); - } } // Scan through all source files in the makefile to extract moc and uic @@ -865,7 +882,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() // The reason is that their file names might be discovered from source files // at generation time. if (this->MocOrUicEnabled()) { - for (cmSourceFile* sf : this->Makefile->GetSourceFiles()) { + for (const auto& sf : this->Makefile->GetSourceFiles()) { // sf->GetExtension() is only valid after sf->ResolveFullPath() ... // Since we're iterating over source files that might be not in the // target we need to check for path errors (not existing files). @@ -877,19 +894,18 @@ bool cmQtAutoGenInitializer::InitScanFiles() std::string const& extLower = cmSystemTools::LowerCase(sf->GetExtension()); - // FIXME: Add a policy to include .hh files. - if (cm->IsHeaderExtension(extLower) && extLower != "hh") { - if (!cmContains(this->AutogenTarget.Headers, sf)) { - auto muf = makeMUFile(sf, fullPath, false); + if (cm->IsHeaderExtension(extLower)) { + if (!cmContains(this->AutogenTarget.Headers, sf.get())) { + auto muf = makeMUFile(sf.get(), fullPath, false); if (muf->SkipMoc || muf->SkipUic) { - this->AutogenTarget.Headers.emplace(sf, std::move(muf)); + addMUHeader(std::move(muf), extLower); } } } else if (cm->IsSourceExtension(extLower)) { - if (!cmContains(this->AutogenTarget.Headers, sf)) { - auto muf = makeMUFile(sf, fullPath, false); + if (!cmContains(this->AutogenTarget.Sources, sf.get())) { + auto muf = makeMUFile(sf.get(), fullPath, false); if (muf->SkipMoc || muf->SkipUic) { - this->AutogenTarget.Sources.emplace(sf, std::move(muf)); + addMUSource(std::move(muf)); } } } else if (this->Uic.Enabled && (extLower == kw.ui)) { @@ -947,6 +963,35 @@ bool cmQtAutoGenInitializer::InitScanFiles() } } + // Generate CMP0100 warning + if (this->MocOrUicEnabled() && + !this->AutogenTarget.CMP0100HeadersWarn.empty()) { + cm::string_view property; + if (this->Moc.Enabled && this->Uic.Enabled) { + property = "SKIP_AUTOGEN"; + } else if (this->Moc.Enabled) { + property = "SKIP_AUTOMOC"; + } else if (this->Uic.Enabled) { + property = "SKIP_AUTOUIC"; + } + std::string files; + for (cmSourceFile* sf : this->AutogenTarget.CMP0100HeadersWarn) { + files += cmStrCat(" ", Quoted(sf->GetFullPath()), '\n'); + } + this->Makefile->IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat( + cmPolicies::GetPolicyWarning(cmPolicies::CMP0100), '\n', + "For compatibility, CMake is excluding the header file(s):\n", files, + "from processing by ", + cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false), + ". If any of the files should be processed, set CMP0100 to NEW. " + "If any of the files should not be processed, " + "explicitly exclude them by setting the source file property ", + property, ":\n set_property(SOURCE file.hh PROPERTY ", property, + " ON)\n")); + } + // Process qrc files if (!this->Rcc.Qrcs.empty()) { const bool modernQt = (this->QtVersion.Major >= 5); @@ -1045,9 +1090,16 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() } // Compose command lines - cmCustomCommandLines commandLines = cmMakeSingleCommandLine( - { cmSystemTools::GetCMakeCommand(), "-E", "cmake_autogen", - this->AutogenTarget.InfoFile, "$<CONFIGURATION>" }); + // TODO: Refactor autogen to output a per-config mocs_compilation.cpp instead + // of fiddling with the include directories + std::vector<std::string> configs; + this->GlobalGen->GetQtAutoGenConfigs(configs); + cmCustomCommandLines commandLines; + for (auto const& config : configs) { + commandLines.push_back(cmMakeCommandLine( + { cmSystemTools::GetCMakeCommand(), "-E", "cmake_autogen", + this->AutogenTarget.InfoFile, config })); + } // Use PRE_BUILD on demand bool usePRE_BUILD = false; @@ -1073,7 +1125,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() if (usePRE_BUILD) { // Add additional autogen target dependencies to origin target for (cmTarget* depTarget : this->AutogenTarget.DependTargets) { - this->GenTarget->Target->AddUtility(depTarget->GetName(), + this->GenTarget->Target->AddUtility(depTarget->GetName(), false, this->Makefile); } @@ -1084,8 +1136,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // PRE_BUILD does not support file dependencies! const std::vector<std::string> no_output; const std::vector<std::string> no_deps; - cmCustomCommand cc(this->Makefile, no_output, autogenProvides, no_deps, - commandLines, autogenComment.c_str(), + cmCustomCommand cc(no_output, autogenProvides, no_deps, commandLines, + this->Makefile->GetBacktrace(), autogenComment.c_str(), this->Dir.Work.c_str()); cc.SetEscapeOldStyle(false); cc.SetEscapeAllowMakeVars(true); @@ -1119,35 +1171,83 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() } } + std::vector<std::string> dependencies( + this->AutogenTarget.DependFiles.begin(), + this->AutogenTarget.DependFiles.end()); + + const bool useNinjaDepfile = this->QtVersion >= IntegerVersion(5, 15) && + this->GlobalGen->GetName().find("Ninja") != std::string::npos; + if (useNinjaDepfile) { + // Create a custom command that generates a timestamp file and + // has a depfile assigned. The depfile is created by JobDepFilesMergeT. + + // Add additional autogen target dependencies + for (const cmTarget* t : this->AutogenTarget.DependTargets) { + dependencies.push_back(t->GetName()); + } + const char timestampFileName[] = "timestamp"; + const std::string outputFile = + cmStrCat(this->Dir.Build, "/", timestampFileName); + this->AutogenTarget.DepFile = cmStrCat(this->Dir.Build, "/deps"); + auto relativeBinaryDir = cmSystemTools::RelativePath( + this->LocalGen->GetBinaryDirectory(), + this->LocalGen->GetCurrentBinaryDirectory()); + if (!relativeBinaryDir.empty()) { + relativeBinaryDir = cmStrCat(relativeBinaryDir, "/"); + } + this->AutogenTarget.DepFileRuleName = + cmStrCat(relativeBinaryDir, this->GenTarget->GetName(), "_autogen/", + timestampFileName); + commandLines.push_back(cmMakeCommandLine( + { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile })); + + this->AddGeneratedSource(outputFile, this->Moc); + const std::string no_main_dependency; + this->LocalGen->AddCustomCommandToOutput( + outputFile, dependencies, no_main_dependency, commandLines, + autogenComment.c_str(), this->Dir.Work.c_str(), /*replace=*/false, + /*escapeOldStyle=*/false, + /*uses_terminal=*/false, + /*command_expand_lists=*/false, this->AutogenTarget.DepFile); + + // Alter variables for the autogen target which now merely wraps the + // custom command + dependencies.clear(); + dependencies.push_back(outputFile); + commandLines.clear(); + autogenComment.clear(); + } + // Create autogen target - cmTarget* autogenTarget = this->Makefile->AddUtilityCommand( - this->AutogenTarget.Name, cmCommandOrigin::Generator, true, - this->Dir.Work.c_str(), /*byproducts=*/autogenProvides, - std::vector<std::string>(this->AutogenTarget.DependFiles.begin(), - this->AutogenTarget.DependFiles.end()), - commandLines, false, autogenComment.c_str()); + cmTarget* autogenTarget = this->LocalGen->AddUtilityCommand( + this->AutogenTarget.Name, true, this->Dir.Work.c_str(), + /*byproducts=*/autogenProvides, + /*depends=*/dependencies, commandLines, false, autogenComment.c_str()); // Create autogen generator target this->LocalGen->AddGeneratorTarget( - new cmGeneratorTarget(autogenTarget, this->LocalGen)); + cm::make_unique<cmGeneratorTarget>(autogenTarget, this->LocalGen)); // Forward origin utilities to autogen target if (this->AutogenTarget.DependOrigin) { - for (BT<std::string> const& depName : this->GenTarget->GetUtilities()) { - autogenTarget->AddUtility(depName.Value, this->Makefile); + for (BT<std::pair<std::string, bool>> const& depName : + this->GenTarget->GetUtilities()) { + autogenTarget->AddUtility(depName.Value.first, false, this->Makefile); } } - // Add additional autogen target dependencies to autogen target - for (cmTarget* depTarget : this->AutogenTarget.DependTargets) { - autogenTarget->AddUtility(depTarget->GetName(), this->Makefile); + if (!useNinjaDepfile) { + // Add additional autogen target dependencies to autogen target + for (cmTarget* depTarget : this->AutogenTarget.DependTargets) { + autogenTarget->AddUtility(depTarget->GetName(), false, this->Makefile); + } } // Set FOLDER property in autogen target if (!this->TargetsFolder.empty()) { - autogenTarget->SetProperty("FOLDER", this->TargetsFolder.c_str()); + autogenTarget->SetProperty("FOLDER", this->TargetsFolder); } // Add autogen target to the origin target dependencies - this->GenTarget->Target->AddUtility(this->AutogenTarget.Name, + this->GenTarget->Target->AddUtility(this->AutogenTarget.Name, false, this->Makefile); // Add autogen target to the global autogen target dependencies @@ -1205,25 +1305,25 @@ bool cmQtAutoGenInitializer::InitRccTargets() ccName += cmStrCat('_', qrc.QrcPathChecksum); } - cmTarget* autoRccTarget = this->Makefile->AddUtilityCommand( - ccName, cmCommandOrigin::Generator, true, this->Dir.Work.c_str(), - ccOutput, ccDepends, commandLines, false, ccComment.c_str()); + cmTarget* autoRccTarget = this->LocalGen->AddUtilityCommand( + ccName, true, this->Dir.Work.c_str(), ccOutput, ccDepends, + commandLines, false, ccComment.c_str()); // Create autogen generator target this->LocalGen->AddGeneratorTarget( - new cmGeneratorTarget(autoRccTarget, this->LocalGen)); + cm::make_unique<cmGeneratorTarget>(autoRccTarget, this->LocalGen)); // Set FOLDER property in autogen target if (!this->TargetsFolder.empty()) { - autoRccTarget->SetProperty("FOLDER", this->TargetsFolder.c_str()); + autoRccTarget->SetProperty("FOLDER", this->TargetsFolder); } if (!this->Rcc.ExecutableTargetName.empty()) { - autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, + autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, false, this->Makefile); } } // Add autogen target to the origin target dependencies - this->GenTarget->Target->AddUtility(ccName, this->Makefile); + this->GenTarget->Target->AddUtility(ccName, false, this->Makefile); // Add autogen target to the global autogen target dependencies if (this->Rcc.GlobalTarget) { @@ -1244,7 +1344,7 @@ bool cmQtAutoGenInitializer::InitRccTargets() } std::string no_main_dependency; cmImplicitDependsList no_implicit_depends; - this->Makefile->AddCustomCommandToOutput( + this->LocalGen->AddCustomCommandToOutput( ccOutput, ccByproducts, ccDepends, no_main_dependency, no_implicit_depends, commandLines, ccComment.c_str(), this->Dir.Work.c_str()); @@ -1356,12 +1456,15 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() info.SetConfig("INCLUDE_DIR", this->Dir.Include); info.SetUInt("QT_VERSION_MAJOR", this->QtVersion.Major); + info.SetUInt("QT_VERSION_MINOR", this->QtVersion.Minor); info.Set("QT_MOC_EXECUTABLE", this->Moc.Executable); info.Set("QT_UIC_EXECUTABLE", this->Uic.Executable); info.Set("CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand()); info.SetConfig("SETTINGS_FILE", this->AutogenTarget.SettingsFile); info.SetConfig("PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile); + info.Set("DEP_FILE", this->AutogenTarget.DepFile); + info.Set("DEP_FILE_RULE_NAME", this->AutogenTarget.DepFileRuleName); info.SetArray("HEADER_EXTENSIONS", this->Makefile->GetCMakeInstance()->GetHeaderExtensions()); info.SetArrayArray( @@ -1528,8 +1631,8 @@ void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName, void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName) { - this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", - fileName.c_str(), false); + this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName, + false); } void cmQtAutoGenInitializer::ConfigFileNames(ConfigString& configString, @@ -1632,21 +1735,39 @@ std::string cmQtAutoGenInitializer::GetMocBuildPath(MUFile const& muf) if (!muf.MocIt) { return res; } - { - std::string const basePath = - cmStrCat(this->PathCheckSum.getPart(muf.FullPath), "/moc_", - FileNameWithoutLastExtension(muf.FullPath)); - std::string suffix; - constexpr std::size_t num_tries_max = 256; - for (std::size_t ii = 0; ii != num_tries_max; ++ii) { - res = cmStrCat(basePath, suffix, ".cpp"); - if (this->Moc.EmittedBuildPaths.emplace(res).second) { - break; - } - // Compute new suffix - suffix = cmStrCat('_', ii + 1); + + std::string basePath = + cmStrCat(this->PathCheckSum.getPart(muf.FullPath), "/moc_", + FileNameWithoutLastExtension(muf.FullPath)); + + res = cmStrCat(basePath, ".cpp"); + if (this->Moc.EmittedBuildPaths.emplace(res).second) { + return res; + } + + // File name already emitted. + // Try appending the header suffix to the base path. + basePath = cmStrCat(basePath, '_', muf.SF->GetExtension()); + res = cmStrCat(basePath, ".cpp"); + if (this->Moc.EmittedBuildPaths.emplace(res).second) { + return res; + } + + // File name with header extension already emitted. + // Try adding a number to the base path. + constexpr std::size_t number_begin = 2; + constexpr std::size_t number_end = 256; + for (std::size_t ii = number_begin; ii != number_end; ++ii) { + res = cmStrCat(basePath, '_', ii, ".cpp"); + if (this->Moc.EmittedBuildPaths.emplace(res).second) { + return res; } } + + // Output file name conflict (unlikely, but still...) + cmSystemTools::Error( + cmStrCat("moc output file name conflict for ", muf.FullPath)); + return res; } diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h index d55259c..48ec1a0 100644 --- a/Source/cmQtAutoGenInitializer.h +++ b/Source/cmQtAutoGenInitializer.h @@ -160,6 +160,8 @@ private: bool MultiConfig = false; bool CMP0071Accept = false; bool CMP0071Warn = false; + bool CMP0100Accept = false; + bool CMP0100Warn = false; std::string ConfigDefault; std::vector<std::string> ConfigsList; std::string TargetsFolder; @@ -189,10 +191,13 @@ private: bool DependOrigin = false; std::set<std::string> DependFiles; std::set<cmTarget*> DependTargets; + std::string DepFile; + std::string DepFileRuleName; // Sources to process std::unordered_map<cmSourceFile*, MUFileHandle> Headers; std::unordered_map<cmSourceFile*, MUFileHandle> Sources; std::vector<MUFile*> FilesGenerated; + std::vector<cmSourceFile*> CMP0100HeadersWarn; } AutogenTarget; /** moc variables. */ diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index f8b8981..893bd6b 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -16,15 +16,17 @@ #include <cm/memory> #include <cm/string_view> +#include <cmext/algorithm> #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" #include "cm_jsoncpp_value.h" -#include "cmAlgorithms.h" #include "cmCryptoHash.h" #include "cmFileTime.h" +#include "cmGccDepfileReader.h" +#include "cmGccDepfileReaderTypes.h" #include "cmGeneratedFileStream.h" #include "cmQtAutoGen.h" #include "cmQtAutoGenerator.h" @@ -170,7 +172,7 @@ public: // -- Attributes // - Config bool MultiConfig = false; - unsigned int QtVersionMajor = 4; + IntegerVersion QtVersion = { 4, 0 }; unsigned int ThreadCount = 0; // - Directories std::string AutogenBuildDir; @@ -179,6 +181,8 @@ public: std::string CMakeExecutable; cmFileTime CMakeExecutableTime; std::string ParseCacheFile; + std::string DepFile; + std::string DepFileRuleName; std::vector<std::string> HeaderExtensions; }; @@ -216,6 +220,7 @@ public: bool SettingsChanged = false; bool RelaxedMode = false; bool PathPrefix = false; + bool CanOutputDependencies = false; cmFileTime ExecutableTime; std::string Executable; std::string CompFileAbs; @@ -485,8 +490,17 @@ public: class JobCompileMocT : public JobCompileT { public: - using JobCompileT::JobCompileT; + JobCompileMocT(MappingHandleT uicMapping, + std::unique_ptr<std::string> reason, + ParseCacheT::FileHandleT cacheEntry) + : JobCompileT(std::move(uicMapping), std::move(reason)) + , CacheEntry(std::move(cacheEntry)) + { + } void Process() override; + + protected: + ParseCacheT::FileHandleT CacheEntry; }; /** uic compiles a file. */ @@ -504,6 +518,12 @@ public: void Process() override; }; + class JobDepFilesMergeT : public JobFenceT + { + private: + void Process() override; + }; + /** @brief The last job. */ class JobFinishT : public JobFenceT { @@ -546,6 +566,9 @@ private: void Abort(bool error); // -- Generation bool CreateDirectories(); + // -- Support for depfiles + static std::vector<std::string> dependenciesFromDepFile( + const char* filePath); private: // -- Settings @@ -808,9 +831,9 @@ void cmQtAutoMocUicT::JobMocPredefsT::Process() // Compose command std::vector<std::string> cmd = MocConst().PredefsCmd; // Add definitions - cmAppend(cmd, MocConst().OptionsDefinitions); + cm::append(cmd, MocConst().OptionsDefinitions); // Add includes - cmAppend(cmd, MocConst().OptionsIncludes); + cm::append(cmd, MocConst().OptionsIncludes); // Execute command if (!RunProcess(GenT::MOC, result, cmd, reason.get())) { LogCommandError(GenT::MOC, @@ -951,7 +974,7 @@ void cmQtAutoMocUicT::JobParseT::MocMacro() void cmQtAutoMocUicT::JobParseT::MocDependecies() { - if (MocConst().DependFilters.empty()) { + if (MocConst().DependFilters.empty() || MocConst().CanOutputDependencies) { return; } @@ -1674,8 +1697,13 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Generate(MappingHandleT const& mapping, if (Probe(*mapping, reason.get())) { // Register the parent directory for creation MocEval().OutputDirs.emplace(cmQtAutoGen::ParentDir(mapping->OutputFile)); + // Fetch the cache entry for the source file + std::string const& sourceFile = mapping->SourceFile->FileName; + ParseCacheT::GetOrInsertT cacheEntry = + BaseEval().ParseCache.GetOrInsert(sourceFile); // Add moc job - Gen()->WorkerPool().EmplaceJob<JobCompileMocT>(mapping, std::move(reason)); + Gen()->WorkerPool().EmplaceJob<JobCompileMocT>( + mapping, std::move(reason), std::move(cacheEntry.first)); // Check if a moc job for a mocs_compilation.cpp entry was generated if (compFile) { MocEval().CompUpdated = true; @@ -1779,6 +1807,14 @@ cmQtAutoMocUicT::JobProbeDepsMocT::FindDependency( std::string const& sourceDir, std::string const& includeString) const { using ResPair = std::pair<std::string, cmFileTime>; + // moc's dependency file contains absolute paths + if (MocConst().CanOutputDependencies) { + ResPair res{ includeString, {} }; + if (res.second.Load(res.first)) { + return res; + } + return {}; + } // Search in vicinity of the source { ResPair res{ sourceDir + includeString, {} }; @@ -1898,6 +1934,11 @@ void cmQtAutoMocUicT::JobProbeDepsFinishT::Process() Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>(); } + if (!BaseConst().DepFile.empty()) { + // Add job to merge dep files + Gen()->WorkerPool().EmplaceJob<JobDepFilesMergeT>(); + } + // Add finish job Gen()->WorkerPool().EmplaceJob<JobFinishT>(); } @@ -1916,9 +1957,9 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() MocConst().OptionsExtra.size() + 16); cmd.push_back(MocConst().Executable); // Add definitions - cmAppend(cmd, MocConst().OptionsDefinitions); + cm::append(cmd, MocConst().OptionsDefinitions); // Add includes - cmAppend(cmd, MocConst().OptionsIncludes); + cm::append(cmd, MocConst().OptionsIncludes); // Add predefs include if (!MocConst().PredefsFileAbs.empty()) { cmd.emplace_back("--include"); @@ -1946,7 +1987,10 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() } } // Add extra options - cmAppend(cmd, MocConst().OptionsExtra); + cm::append(cmd, MocConst().OptionsExtra); + if (MocConst().CanOutputDependencies) { + cmd.emplace_back("--output-dep-file"); + } // Add output file cmd.emplace_back("-o"); cmd.push_back(outputFile); @@ -1956,12 +2000,7 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() // Execute moc command cmWorkerPool::ProcessResultT result; - if (RunProcess(GenT::MOC, result, cmd, Reason.get())) { - // Moc command success. Print moc output. - if (!result.StdOut.empty()) { - Log().Info(GenT::MOC, result.StdOut); - } - } else { + if (!RunProcess(GenT::MOC, result, cmd, Reason.get())) { // Moc command failed std::string includers; if (!Mapping->IncluderFiles.empty()) { @@ -1976,6 +2015,28 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() MessagePath(outputFile), '\n', includers, result.ErrorMessage), cmd, result.StdOut); + return; + } + + // Moc command success. Print moc output. + if (!result.StdOut.empty()) { + Log().Info(GenT::MOC, result.StdOut); + } + + // Extract dependencies from the dep file moc generated for us + if (MocConst().CanOutputDependencies) { + const std::string depfile = outputFile + ".d"; + if (Log().Verbose()) { + Log().Info(GenT::MOC, + "Reading dependencies from " + MessagePath(depfile)); + } + if (!cmSystemTools::FileExists(depfile)) { + Log().Warning(GenT::MOC, + "Dependency file " + MessagePath(depfile) + + " does not exist."); + return; + } + CacheEntry->Moc.Depends = dependenciesFromDepFile(depfile.c_str()); } } @@ -1992,9 +2053,9 @@ void cmQtAutoMocUicT::JobCompileUicT::Process() auto optionIt = UicConst().UiFiles.find(sourceFile); if (optionIt != UicConst().UiFiles.end()) { UicMergeOptions(allOpts, optionIt->second.Options, - (BaseConst().QtVersionMajor == 5)); + (BaseConst().QtVersion.Major == 5)); } - cmAppend(cmd, allOpts); + cm::append(cmd, allOpts); } cmd.emplace_back("-o"); cmd.emplace_back(outputFile); @@ -2067,6 +2128,106 @@ void cmQtAutoMocUicT::JobMocsCompilationT::Process() } } +/* + * Escapes paths for Ninja depfiles. + * This is a re-implementation of what moc does when writing depfiles. + */ +std::string escapeDependencyPath(cm::string_view path) +{ + std::string escapedPath; + escapedPath.reserve(path.size()); + const size_t s = path.size(); + int backslashCount = 0; + for (size_t i = 0; i < s; ++i) { + if (path[i] == '\\') { + ++backslashCount; + } else { + if (path[i] == '$') { + escapedPath.push_back('$'); + } else if (path[i] == '#') { + escapedPath.push_back('\\'); + } else if (path[i] == ' ') { + // Double the amount of written backslashes, + // and add one more to escape the space. + while (backslashCount-- >= 0) { + escapedPath.push_back('\\'); + } + } + backslashCount = 0; + } + escapedPath.push_back(path[i]); + } + return escapedPath; +} + +void cmQtAutoMocUicT::JobDepFilesMergeT::Process() +{ + if (Log().Verbose()) { + Log().Info(GenT::MOC, "Merging MOC dependencies"); + } + auto processDepFile = + [](const std::string& mocOutputFile) -> std::vector<std::string> { + std::string f = mocOutputFile + ".d"; + if (!cmSystemTools::FileExists(f)) { + return {}; + } + return dependenciesFromDepFile(f.c_str()); + }; + + std::vector<std::string> dependencies; + ParseCacheT& parseCache = BaseEval().ParseCache; + auto processMappingEntry = [&](const MappingMapT::value_type& m) { + auto cacheEntry = parseCache.GetOrInsert(m.first); + if (cacheEntry.first->Moc.Depends.empty()) { + cacheEntry.first->Moc.Depends = processDepFile(m.second->OutputFile); + } + dependencies.insert(dependencies.end(), + cacheEntry.first->Moc.Depends.begin(), + cacheEntry.first->Moc.Depends.end()); + }; + + std::for_each(MocEval().HeaderMappings.begin(), + MocEval().HeaderMappings.end(), processMappingEntry); + std::for_each(MocEval().SourceMappings.begin(), + MocEval().SourceMappings.end(), processMappingEntry); + + // Remove duplicates to make the depfile smaller + std::sort(dependencies.begin(), dependencies.end()); + dependencies.erase(std::unique(dependencies.begin(), dependencies.end()), + dependencies.end()); + + // Add form files + for (const auto& uif : UicEval().UiFiles) { + dependencies.push_back(uif.first); + } + + // Write the file + cmsys::ofstream ofs; + ofs.open(BaseConst().DepFile.c_str(), + (std::ios::out | std::ios::binary | std::ios::trunc)); + if (!ofs) { + LogError(GenT::GEN, + cmStrCat("Cannot open ", MessagePath(BaseConst().DepFile), + " for writing.")); + return; + } + ofs << BaseConst().DepFileRuleName << ": \\" << std::endl; + for (const std::string& file : dependencies) { + ofs << '\t' << escapeDependencyPath(file) << " \\" << std::endl; + if (!ofs.good()) { + LogError(GenT::GEN, + cmStrCat("Writing depfile", MessagePath(BaseConst().DepFile), + " failed.")); + return; + } + } + + // Add the CMake executable to re-new cache data if necessary. + // Also, this is the last entry, so don't add a backslash. + ofs << '\t' << escapeDependencyPath(BaseConst().CMakeExecutable) + << std::endl; +} + void cmQtAutoMocUicT::JobFinishT::Process() { Gen()->AbortSuccess(); @@ -2082,7 +2243,8 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) { // -- Required settings if (!info.GetBool("MULTI_CONFIG", BaseConst_.MultiConfig, true) || - !info.GetUInt("QT_VERSION_MAJOR", BaseConst_.QtVersionMajor, true) || + !info.GetUInt("QT_VERSION_MAJOR", BaseConst_.QtVersion.Major, true) || + !info.GetUInt("QT_VERSION_MINOR", BaseConst_.QtVersion.Minor, true) || !info.GetUInt("PARALLEL", BaseConst_.ThreadCount, false) || !info.GetString("BUILD_DIR", BaseConst_.AutogenBuildDir, true) || !info.GetStringConfig("INCLUDE_DIR", BaseConst_.AutogenIncludeDir, @@ -2090,6 +2252,9 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) !info.GetString("CMAKE_EXECUTABLE", BaseConst_.CMakeExecutable, true) || !info.GetStringConfig("PARSE_CACHE_FILE", BaseConst_.ParseCacheFile, true) || + !info.GetString("DEP_FILE", BaseConst_.DepFile, false) || + !info.GetString("DEP_FILE_RULE_NAME", BaseConst_.DepFileRuleName, + false) || !info.GetStringConfig("SETTINGS_FILE", SettingsFile_, true) || !info.GetArray("HEADER_EXTENSIONS", BaseConst_.HeaderExtensions, true) || !info.GetString("QT_MOC_EXECUTABLE", MocConst_.Executable, false) || @@ -2143,8 +2308,10 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) MocConst_.MacroFilters.emplace_back( item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]")); } - // Dependency filters - { + // Can moc output dependencies or do we need to setup dependency filters? + if (BaseConst_.QtVersion >= IntegerVersion(5, 15)) { + MocConst_.CanOutputDependencies = true; + } else { Json::Value const& val = info.GetValue("MOC_DEPEND_FILTERS"); if (!val.isArray()) { return info.LogError("MOC_DEPEND_FILTERS JSON value is not an array."); @@ -2660,6 +2827,19 @@ bool cmQtAutoMocUicT::CreateDirectories() return true; } +std::vector<std::string> cmQtAutoMocUicT::dependenciesFromDepFile( + const char* filePath) +{ + cmGccDepfileContent content = cmReadGccDepfile(filePath); + if (content.empty()) { + return {}; + } + + // Moc outputs a depfile with exactly one rule. + // Discard the rule and return the dependencies. + return content.front().paths; +} + void cmQtAutoMocUicT::Abort(bool error) { if (error) { diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx index 3af81ad..08eb4b5 100644 --- a/Source/cmQtAutoRcc.cxx +++ b/Source/cmQtAutoRcc.cxx @@ -6,7 +6,8 @@ #include <string> #include <vector> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmCryptoHash.h" #include "cmDuration.h" #include "cmFileLock.h" @@ -405,7 +406,7 @@ bool cmQtAutoRccT::GenerateRcc() // Compose rcc command std::vector<std::string> cmd; cmd.push_back(RccExecutable_); - cmAppend(cmd, Options_); + cm::append(cmd, Options_); cmd.emplace_back("-o"); cmd.push_back(RccFileOutput_); cmd.push_back(QrcFile_); diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index 0a1d109..5ab1b3a 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -85,6 +85,11 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( return replaceValues.ObjectsQuoted; } } + if (replaceValues.AIXExports) { + if (variable == "AIX_EXPORTS") { + return replaceValues.AIXExports; + } + } if (replaceValues.Defines && variable == "DEFINES") { return replaceValues.Defines; } diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index 8f36196..09e8a3b 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -36,6 +36,7 @@ public: const char* TargetVersionMajor; const char* TargetVersionMinor; const char* Language; + const char* AIXExports; const char* Objects; const char* Target; const char* LinkLibraries; diff --git a/Source/cmScriptGenerator.h b/Source/cmScriptGenerator.h index c8bb1ab..7d676c9 100644 --- a/Source/cmScriptGenerator.h +++ b/Source/cmScriptGenerator.h @@ -71,7 +71,7 @@ protected: std::string CreateConfigTest(const std::string& config); std::string CreateConfigTest(std::vector<std::string> const& configs); - std::string CreateComponentTest(const char* component); + std::string CreateComponentTest(const std::string& component); // Information shared by most generator types. std::string RuntimeConfigVariable; diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx index d15ce57..766d347 100644 --- a/Source/cmSearchPath.cxx +++ b/Source/cmSearchPath.cxx @@ -181,7 +181,13 @@ void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths, const char* arch = this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE"); if (arch && *arch) { - this->AddPathInternal(dir + subdir + "/" + arch, base); + if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") && + this->FC->Makefile->IsDefinitionSet( + "CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) { + this->AddPathInternal(cmStrCat('/', arch, dir, subdir), base); + } else { + this->AddPathInternal(cmStrCat(dir, subdir, '/', arch), base); + } } } std::string add = dir + subdir; diff --git a/Source/cmSearchPath.h b/Source/cmSearchPath.h index 2a576ed..3ecc73b 100644 --- a/Source/cmSearchPath.h +++ b/Source/cmSearchPath.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <set> #include <string> #include <vector> @@ -27,6 +28,7 @@ public: ~cmSearchPath(); const std::vector<std::string>& GetPaths() const { return this->Paths; } + std::size_t size() const { return this->Paths.size(); } void ExtractWithout(const std::set<std::string>& ignore, std::vector<std::string>& outPaths, diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx index 3b2e5f3..434fb68 100644 --- a/Source/cmServer.cxx +++ b/Source/cmServer.cxx @@ -59,16 +59,12 @@ cmServer::cmServer(cmConnection* conn, bool supportExperimental) , SupportExperimental(supportExperimental) { // Register supported protocols: - this->RegisterProtocol(new cmServerProtocol1); + this->RegisterProtocol(cm::make_unique<cmServerProtocol1>()); } cmServer::~cmServer() { Close(); - - for (cmServerProtocol* p : this->SupportedProtocols) { - delete p; - } } void cmServer::ProcessRequest(cmConnection* connection, @@ -117,22 +113,22 @@ void cmServer::ProcessRequest(cmConnection* connection, } } -void cmServer::RegisterProtocol(cmServerProtocol* protocol) +void cmServer::RegisterProtocol(std::unique_ptr<cmServerProtocol> protocol) { if (protocol->IsExperimental() && !this->SupportExperimental) { - delete protocol; + protocol.reset(); return; } auto version = protocol->ProtocolVersion(); assert(version.first >= 0); assert(version.second >= 0); - auto it = std::find_if(this->SupportedProtocols.begin(), - this->SupportedProtocols.end(), - [version](cmServerProtocol* p) { - return p->ProtocolVersion() == version; - }); + auto it = std::find_if( + this->SupportedProtocols.begin(), this->SupportedProtocols.end(), + [version](const std::unique_ptr<cmServerProtocol>& p) { + return p->ProtocolVersion() == version; + }); if (it == this->SupportedProtocols.end()) { - this->SupportedProtocols.push_back(protocol); + this->SupportedProtocols.push_back(std::move(protocol)); } } @@ -297,19 +293,20 @@ void cmServer::WriteJsonObject(cmConnection* connection, } cmServerProtocol* cmServer::FindMatchingProtocol( - const std::vector<cmServerProtocol*>& protocols, int major, int minor) + const std::vector<std::unique_ptr<cmServerProtocol>>& protocols, int major, + int minor) { cmServerProtocol* bestMatch = nullptr; - for (auto protocol : protocols) { + for (const auto& protocol : protocols) { auto version = protocol->ProtocolVersion(); if (major != version.first) { continue; } if (minor == version.second) { - return protocol; + return protocol.get(); } if (!bestMatch || bestMatch->ProtocolVersion().second < version.second) { - bestMatch = protocol; + bestMatch = protocol.get(); } } return minor < 0 ? bestMatch : nullptr; diff --git a/Source/cmServer.h b/Source/cmServer.h index 3d7027b..ec40738 100644 --- a/Source/cmServer.h +++ b/Source/cmServer.h @@ -103,7 +103,7 @@ public: cmFileMonitor* FileMonitor() const; private: - void RegisterProtocol(cmServerProtocol* protocol); + void RegisterProtocol(std::unique_ptr<cmServerProtocol> protocol); // Callbacks from cmServerConnection: @@ -149,12 +149,13 @@ private: const DebugInfo* debug) const; static cmServerProtocol* FindMatchingProtocol( - const std::vector<cmServerProtocol*>& protocols, int major, int minor); + const std::vector<std::unique_ptr<cmServerProtocol>>& protocols, int major, + int minor); const bool SupportExperimental; cmServerProtocol* Protocol = nullptr; - std::vector<cmServerProtocol*> SupportedProtocols; + std::vector<std::unique_ptr<cmServerProtocol>> SupportedProtocols; friend class cmServerProtocol; friend class cmServerRequest; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index 56003df..1d4ea01 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -744,7 +744,7 @@ void cmServerProtocol1::GeneratorInformation::SetupGenerator( cm->SetHomeDirectory(SourceDirectory); cm->SetHomeOutputDirectory(BuildDirectory); - cmGlobalGenerator* gg = cm->CreateGlobalGenerator(fullGeneratorName); + auto gg = cm->CreateGlobalGenerator(fullGeneratorName); if (!gg) { setErrorMessage( errorMessage, @@ -753,7 +753,7 @@ void cmServerProtocol1::GeneratorInformation::SetupGenerator( return; } - cm->SetGlobalGenerator(gg); + cm->SetGlobalGenerator(std::move(gg)); cm->SetGeneratorToolset(Toolset); cm->SetGeneratorPlatform(Platform); diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx index 8c3a4cb..d8927e8 100644 --- a/Source/cmSetCommand.cxx +++ b/Source/cmSetCommand.cxx @@ -121,7 +121,7 @@ bool cmSetCommand(std::vector<std::string> const& args, if (cache) { std::string::size_type cacheStart = args.size() - 3 - (force ? 1 : 0); - if (!cmState::StringToCacheEntryType(args[cacheStart + 1].c_str(), type)) { + if (!cmState::StringToCacheEntryType(args[cacheStart + 1], type)) { std::string m = "implicitly converting '" + args[cacheStart + 1] + "' to 'STRING' type."; status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, m); @@ -149,8 +149,8 @@ bool cmSetCommand(std::vector<std::string> const& args, // if it is meant to be in the cache then define it in the cache if (cache) { - status.GetMakefile().AddCacheDefinition(variable, value.c_str(), docstring, - type, force); + status.GetMakefile().AddCacheDefinition(variable, value, docstring, type, + force); } else { // add the definition status.GetMakefile().AddDefinition(variable, value); diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx index 112d832..ce534e1 100644 --- a/Source/cmSetPropertyCommand.cxx +++ b/Source/cmSetPropertyCommand.cxx @@ -194,9 +194,8 @@ namespace { bool HandleGlobalMode(cmExecutionStatus& status, const std::set<std::string>& names, const std::string& propertyName, - const std::string& propertyValue, - const bool appendAsString, const bool appendMode, - const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { if (!names.empty()) { status.SetError("given names for GLOBAL scope."); @@ -205,14 +204,14 @@ bool HandleGlobalMode(cmExecutionStatus& status, // Set or append the property. cmake* cm = status.GetMakefile().GetCMakeInstance(); - const char* value = propertyValue.c_str(); - if (remove) { - value = nullptr; - } if (appendMode) { - cm->AppendProperty(propertyName, value ? value : "", appendAsString); + cm->AppendProperty(propertyName, propertyValue, appendAsString); } else { - cm->SetProperty(propertyName, value); + if (remove) { + cm->SetProperty(propertyName, nullptr); + } else { + cm->SetProperty(propertyName, propertyValue.c_str()); + } } return true; @@ -221,9 +220,8 @@ bool HandleGlobalMode(cmExecutionStatus& status, bool HandleDirectoryMode(cmExecutionStatus& status, const std::set<std::string>& names, const std::string& propertyName, - const std::string& propertyValue, - const bool appendAsString, const bool appendMode, - const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { if (names.size() > 1) { status.SetError("allows at most one name for DIRECTORY scope."); @@ -258,14 +256,14 @@ bool HandleDirectoryMode(cmExecutionStatus& status, } // Set or append the property. - const char* value = propertyValue.c_str(); - if (remove) { - value = nullptr; - } if (appendMode) { - mf->AppendProperty(propertyName, value ? value : "", appendAsString); + mf->AppendProperty(propertyName, propertyValue, appendAsString); } else { - mf->SetProperty(propertyName, value); + if (remove) { + mf->SetProperty(propertyName, nullptr); + } else { + mf->SetProperty(propertyName, propertyValue.c_str()); + } } return true; @@ -274,9 +272,8 @@ bool HandleDirectoryMode(cmExecutionStatus& status, bool HandleTargetMode(cmExecutionStatus& status, const std::set<std::string>& names, const std::string& propertyName, - const std::string& propertyValue, - const bool appendAsString, const bool appendMode, - const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { for (std::string const& name : names) { if (status.GetMakefile().IsAlias(name)) { @@ -300,18 +297,18 @@ bool HandleTargetMode(cmExecutionStatus& status, bool HandleTarget(cmTarget* target, cmMakefile& makefile, const std::string& propertyName, - const std::string& propertyValue, const bool appendAsString, - const bool appendMode, const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { // Set or append the property. - const char* value = propertyValue.c_str(); - if (remove) { - value = nullptr; - } if (appendMode) { - target->AppendProperty(propertyName, value, appendAsString); + target->AppendProperty(propertyName, propertyValue, appendAsString); } else { - target->SetProperty(propertyName, value); + if (remove) { + target->SetProperty(propertyName, nullptr); + } else { + target->SetProperty(propertyName, propertyValue); + } } // Check the resulting value. @@ -323,9 +320,8 @@ bool HandleTarget(cmTarget* target, cmMakefile& makefile, bool HandleSourceMode(cmExecutionStatus& status, const std::set<std::string>& names, const std::string& propertyName, - const std::string& propertyValue, - const bool appendAsString, const bool appendMode, - const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { for (std::string const& name : names) { // Get the source file. @@ -344,28 +340,26 @@ bool HandleSourceMode(cmExecutionStatus& status, } bool HandleSource(cmSourceFile* sf, const std::string& propertyName, - const std::string& propertyValue, const bool appendAsString, - const bool appendMode, const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { // Set or append the property. - const char* value = propertyValue.c_str(); - if (remove) { - value = nullptr; - } - if (appendMode) { - sf->AppendProperty(propertyName, value, appendAsString); + sf->AppendProperty(propertyName, propertyValue, appendAsString); } else { - sf->SetProperty(propertyName, value); + if (remove) { + sf->SetProperty(propertyName, nullptr); + } else { + sf->SetProperty(propertyName, propertyValue.c_str()); + } } return true; } bool HandleTestMode(cmExecutionStatus& status, std::set<std::string>& names, const std::string& propertyName, - const std::string& propertyValue, - const bool appendAsString, const bool appendMode, - const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { // Look for tests with all names given. std::set<std::string>::iterator next; @@ -396,18 +390,18 @@ bool HandleTestMode(cmExecutionStatus& status, std::set<std::string>& names, } bool HandleTest(cmTest* test, const std::string& propertyName, - const std::string& propertyValue, const bool appendAsString, - const bool appendMode, const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { // Set or append the property. - const char* value = propertyValue.c_str(); - if (remove) { - value = nullptr; - } if (appendMode) { - test->AppendProperty(propertyName, value, appendAsString); + test->AppendProperty(propertyName, propertyValue, appendAsString); } else { - test->SetProperty(propertyName, value); + if (remove) { + test->SetProperty(propertyName, nullptr); + } else { + test->SetProperty(propertyName, propertyValue.c_str()); + } } return true; @@ -416,9 +410,8 @@ bool HandleTest(cmTest* test, const std::string& propertyName, bool HandleCacheMode(cmExecutionStatus& status, const std::set<std::string>& names, const std::string& propertyName, - const std::string& propertyValue, - const bool appendAsString, const bool appendMode, - const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { if (propertyName == "ADVANCED") { if (!remove && !cmIsOn(propertyValue) && !cmIsOff(propertyValue)) { @@ -463,21 +456,19 @@ bool HandleCacheMode(cmExecutionStatus& status, bool HandleCacheEntry(std::string const& cacheKey, const cmMakefile& makefile, const std::string& propertyName, - const std::string& propertyValue, - const bool appendAsString, const bool appendMode, - const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { // Set or append the property. - const char* value = propertyValue.c_str(); cmState* state = makefile.GetState(); if (remove) { state->RemoveCacheEntryProperty(cacheKey, propertyName); } if (appendMode) { - state->AppendCacheEntryProperty(cacheKey, propertyName, value, + state->AppendCacheEntryProperty(cacheKey, propertyName, propertyValue, appendAsString); } else { - state->SetCacheEntryProperty(cacheKey, propertyName, value); + state->SetCacheEntryProperty(cacheKey, propertyName, propertyValue); } return true; @@ -486,9 +477,8 @@ bool HandleCacheEntry(std::string const& cacheKey, const cmMakefile& makefile, bool HandleInstallMode(cmExecutionStatus& status, const std::set<std::string>& names, const std::string& propertyName, - const std::string& propertyValue, - const bool appendAsString, const bool appendMode, - const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { cmake* cm = status.GetMakefile().GetCMakeInstance(); @@ -510,17 +500,17 @@ bool HandleInstallMode(cmExecutionStatus& status, bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile, const std::string& propertyName, - const std::string& propertyValue, const bool appendAsString, - const bool appendMode, const bool remove) + const std::string& propertyValue, bool appendAsString, + bool appendMode, bool remove) { // Set or append the property. - const char* value = propertyValue.c_str(); if (remove) { file->RemoveProperty(propertyName); } else if (appendMode) { - file->AppendProperty(&makefile, propertyName, value, appendAsString); + file->AppendProperty(&makefile, propertyName, propertyValue, + appendAsString); } else { - file->SetProperty(&makefile, propertyName, value); + file->SetProperty(&makefile, propertyName, propertyValue); } return true; } diff --git a/Source/cmSetTargetPropertiesCommand.cxx b/Source/cmSetTargetPropertiesCommand.cxx index 8d917db..cd0fa40 100644 --- a/Source/cmSetTargetPropertiesCommand.cxx +++ b/Source/cmSetTargetPropertiesCommand.cxx @@ -4,7 +4,8 @@ #include <iterator> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" @@ -33,7 +34,7 @@ bool cmSetTargetPropertiesCommand(std::vector<std::string> const& args, status.SetError("called with incorrect number of arguments."); return false; } - cmAppend(propertyPairs, j, args.end()); + cm::append(propertyPairs, j, args.end()); break; } numFiles++; @@ -70,7 +71,7 @@ static bool SetOneTarget(const std::string& tname, // now loop through all the props and set them unsigned int k; for (k = 0; k < propertyPairs.size(); k = k + 2) { - target->SetProperty(propertyPairs[k], propertyPairs[k + 1].c_str()); + target->SetProperty(propertyPairs[k], propertyPairs[k + 1]); target->CheckProperty(propertyPairs[k], mf); } } diff --git a/Source/cmSetTestsPropertiesCommand.cxx b/Source/cmSetTestsPropertiesCommand.cxx index de61eda..2e7aeca 100644 --- a/Source/cmSetTestsPropertiesCommand.cxx +++ b/Source/cmSetTestsPropertiesCommand.cxx @@ -4,7 +4,8 @@ #include <iterator> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" @@ -36,7 +37,7 @@ bool cmSetTestsPropertiesCommand(std::vector<std::string> const& args, status.SetError("called with incorrect number of arguments."); return false; } - cmAppend(propertyPairs, j, args.end()); + cm::append(propertyPairs, j, args.end()); break; } numFiles++; diff --git a/Source/cmSiteNameCommand.cxx b/Source/cmSiteNameCommand.cxx index d47f121..b2d905e 100644 --- a/Source/cmSiteNameCommand.cxx +++ b/Source/cmSiteNameCommand.cxx @@ -72,8 +72,7 @@ bool cmSiteNameCommand(std::vector<std::string> const& args, } #endif status.GetMakefile().AddCacheDefinition( - args[0], siteName.c_str(), - "Name of the computer/site where compile is being run", + args[0], siteName, "Name of the computer/site where compile is being run", cmStateEnums::STRING); return true; diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index 2a345eb..fd9cacd 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -128,7 +128,7 @@ bool cmSourceFile::FindFullPath(std::string* error) // The file is not generated. It must exist on disk. cmMakefile const* makefile = this->Location.GetMakefile(); // Location path - std::string const lPath = this->Location.GetFullPath(); + std::string const& lPath = this->Location.GetFullPath(); // List of extension lists std::array<std::vector<std::string> const*, 2> const extsLists = { { &makefile->GetCMakeInstance()->GetSourceExtensions(), @@ -145,7 +145,7 @@ bool cmSourceFile::FindFullPath(std::string* error) return true; } // Try full path with extension - for (auto exts : extsLists) { + for (auto& exts : extsLists) { for (std::string const& ext : *exts) { if (!ext.empty()) { std::string extPath = cmStrCat(fullPath, '.', ext); @@ -260,21 +260,21 @@ void cmSourceFile::SetProperty(const std::string& prop, const char* value) } } -void cmSourceFile::AppendProperty(const std::string& prop, const char* value, - bool asString) +void cmSourceFile::AppendProperty(const std::string& prop, + const std::string& value, bool asString) { if (prop == propINCLUDE_DIRECTORIES) { - if (value && *value) { + if (!value.empty()) { cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace(); this->IncludeDirectories.emplace_back(value, lfbt); } } else if (prop == propCOMPILE_OPTIONS) { - if (value && *value) { + if (!value.empty()) { cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace(); this->CompileOptions.emplace_back(value, lfbt); } } else if (prop == propCOMPILE_DEFINITIONS) { - if (value && *value) { + if (!value.empty()) { cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace(); this->CompileDefinitions.emplace_back(value, lfbt); } diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h index 82a3625..e22829f 100644 --- a/Source/cmSourceFile.h +++ b/Source/cmSourceFile.h @@ -42,7 +42,7 @@ public: //! Set/Get a property of this source file void SetProperty(const std::string& prop, const char* value); - void AppendProperty(const std::string& prop, const char* value, + void AppendProperty(const std::string& prop, const std::string& value, bool asString = false); //! Might return a nullptr if the property is not set or invalid const char* GetProperty(const std::string& prop) const; @@ -154,9 +154,8 @@ private: #define CM_HEADER_REGEX "\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$" #define CM_SOURCE_REGEX \ - "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|cu|f|f90|for|fpp|ftn|m|mm|rc|def|r|odl|idl|" \ - "hpj" \ - "|bat)$" + "\\.(C|F|M|c|c\\+\\+|cc|cpp|cxx|cu|f|f90|for|fpp|ftn|m|mm|" \ + "rc|def|r|odl|idl|hpj|bat)$" #define CM_PCH_REGEX "cmake_pch\\.(h|hxx)$" diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx index df702b0..5f807b8 100644 --- a/Source/cmSourceFileLocation.cxx +++ b/Source/cmSourceFileLocation.cxx @@ -31,7 +31,8 @@ cmSourceFileLocation::cmSourceFileLocation(cmMakefile const* mf, this->AmbiguousExtension = true; this->Directory = cmSystemTools::GetFilenamePath(name); if (cmSystemTools::FileIsFullPath(this->Directory)) { - this->Directory = cmSystemTools::CollapseFullPath(this->Directory); + this->Directory = cmSystemTools::CollapseFullPath( + this->Directory, mf->GetHomeOutputDirectory()); } this->Name = cmSystemTools::GetFilenameName(name); if (kind == cmSourceFileLocationKind::Known) { diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx index 8c3ec9f..155068cb 100644 --- a/Source/cmSourceGroup.cxx +++ b/Source/cmSourceGroup.cxx @@ -4,6 +4,8 @@ #include <utility> +#include <cm/memory> + #include "cmStringAlgorithms.h" class cmSourceGroupInternals @@ -16,7 +18,7 @@ cmSourceGroup::cmSourceGroup(std::string name, const char* regex, const char* parentName) : Name(std::move(name)) { - this->Internal = new cmSourceGroupInternals; + this->Internal = cm::make_unique<cmSourceGroupInternals>(); this->SetGroupRegex(regex); if (parentName) { this->FullName = cmStrCat(parentName, '\\'); @@ -24,10 +26,7 @@ cmSourceGroup::cmSourceGroup(std::string name, const char* regex, this->FullName += this->Name; } -cmSourceGroup::~cmSourceGroup() -{ - delete this->Internal; -} +cmSourceGroup::~cmSourceGroup() = default; cmSourceGroup::cmSourceGroup(cmSourceGroup const& r) { @@ -36,7 +35,7 @@ cmSourceGroup::cmSourceGroup(cmSourceGroup const& r) this->GroupRegex = r.GroupRegex; this->GroupFiles = r.GroupFiles; this->SourceFiles = r.SourceFiles; - this->Internal = new cmSourceGroupInternals(*r.Internal); + this->Internal = cm::make_unique<cmSourceGroupInternals>(*r.Internal); } cmSourceGroup& cmSourceGroup::operator=(cmSourceGroup const& r) diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h index 581dc5d..623cded 100644 --- a/Source/cmSourceGroup.h +++ b/Source/cmSourceGroup.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <memory> #include <set> #include <string> #include <vector> @@ -122,7 +123,7 @@ private: */ std::vector<const cmSourceFile*> SourceFiles; - cmSourceGroupInternals* Internal; + std::unique_ptr<cmSourceGroupInternals> Internal; }; #endif diff --git a/Source/cmState.cxx b/Source/cmState.cxx index f9b5ed1..9fc7615 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -3,9 +3,9 @@ #include "cmState.h" #include <algorithm> +#include <array> #include <cassert> #include <cstdlib> -#include <cstring> #include <utility> #include <cm/memory> @@ -60,43 +60,44 @@ const char* cmState::GetTargetTypeName(cmStateEnums::TargetType targetType) return nullptr; } -const char* cmCacheEntryTypes[] = { "BOOL", "PATH", "FILEPATH", - "STRING", "INTERNAL", "STATIC", - "UNINITIALIZED", nullptr }; +static const std::array<std::string, 7> cmCacheEntryTypes = { + { "BOOL", "PATH", "FILEPATH", "STRING", "INTERNAL", "STATIC", + "UNINITIALIZED" } +}; -const char* cmState::CacheEntryTypeToString(cmStateEnums::CacheEntryType type) +const std::string& cmState::CacheEntryTypeToString( + cmStateEnums::CacheEntryType type) { - if (type > 6) { - return cmCacheEntryTypes[6]; + if (type < cmStateEnums::BOOL || type > cmStateEnums::UNINITIALIZED) { + type = cmStateEnums::UNINITIALIZED; } return cmCacheEntryTypes[type]; } -cmStateEnums::CacheEntryType cmState::StringToCacheEntryType(const char* s) +cmStateEnums::CacheEntryType cmState::StringToCacheEntryType( + const std::string& s) { cmStateEnums::CacheEntryType type = cmStateEnums::STRING; StringToCacheEntryType(s, type); return type; } -bool cmState::StringToCacheEntryType(const char* s, +bool cmState::StringToCacheEntryType(const std::string& s, cmStateEnums::CacheEntryType& type) { - int i = 0; - while (cmCacheEntryTypes[i]) { - if (strcmp(s, cmCacheEntryTypes[i]) == 0) { + for (size_t i = 0; i < cmCacheEntryTypes.size(); ++i) { + if (s == cmCacheEntryTypes[i]) { type = static_cast<cmStateEnums::CacheEntryType>(i); return true; } - ++i; } return false; } bool cmState::IsCacheEntryType(std::string const& key) { - for (int i = 0; cmCacheEntryTypes[i]; ++i) { - if (key == cmCacheEntryTypes[i]) { + for (const std::string& i : cmCacheEntryTypes) { + if (key == i) { return true; } } @@ -140,6 +141,16 @@ const char* cmState::GetCacheEntryValue(std::string const& key) const return e->Value.c_str(); } +std::string cmState::GetSafeCacheEntryValue(std::string const& key) const +{ + std::string retval; + auto val = this->GetCacheEntryValue(key); + if (val) { + retval = val; + } + return retval; +} + const std::string* cmState::GetInitializedCacheValue( std::string const& key) const { @@ -149,8 +160,7 @@ const std::string* cmState::GetInitializedCacheValue( cmStateEnums::CacheEntryType cmState::GetCacheEntryType( std::string const& key) const { - cmCacheManager::CacheIterator it = - this->CacheManager->GetCacheIterator(key.c_str()); + cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key); return it.GetType(); } @@ -164,8 +174,7 @@ void cmState::SetCacheEntryProperty(std::string const& key, std::string const& propertyName, std::string const& value) { - cmCacheManager::CacheIterator it = - this->CacheManager->GetCacheIterator(key.c_str()); + cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key); it.SetProperty(propertyName, value.c_str()); } @@ -173,24 +182,21 @@ void cmState::SetCacheEntryBoolProperty(std::string const& key, std::string const& propertyName, bool value) { - cmCacheManager::CacheIterator it = - this->CacheManager->GetCacheIterator(key.c_str()); + cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key); it.SetProperty(propertyName, value); } std::vector<std::string> cmState::GetCacheEntryPropertyList( const std::string& key) { - cmCacheManager::CacheIterator it = - this->CacheManager->GetCacheIterator(key.c_str()); + cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key); return it.GetPropertyList(); } const char* cmState::GetCacheEntryProperty(std::string const& key, std::string const& propertyName) { - cmCacheManager::CacheIterator it = - this->CacheManager->GetCacheIterator(key.c_str()); + cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key); if (!it.PropertyExists(propertyName)) { return nullptr; } @@ -200,8 +206,8 @@ const char* cmState::GetCacheEntryProperty(std::string const& key, bool cmState::GetCacheEntryPropertyAsBool(std::string const& key, std::string const& propertyName) { - return this->CacheManager->GetCacheIterator(key.c_str()) - .GetPropertyAsBool(propertyName); + return this->CacheManager->GetCacheIterator(key).GetPropertyAsBool( + propertyName); } void cmState::AddCacheEntry(const std::string& key, const char* value, @@ -253,15 +259,14 @@ void cmState::AppendCacheEntryProperty(const std::string& key, const std::string& property, const std::string& value, bool asString) { - this->CacheManager->GetCacheIterator(key.c_str()) - .AppendProperty(property, value.c_str(), asString); + this->CacheManager->GetCacheIterator(key).AppendProperty(property, value, + asString); } void cmState::RemoveCacheEntryProperty(std::string const& key, std::string const& propertyName) { - this->CacheManager->GetCacheIterator(key.c_str()) - .SetProperty(propertyName, nullptr); + this->CacheManager->GetCacheIterator(key).SetProperty(propertyName, nullptr); } cmStateSnapshot cmState::Reset() @@ -562,8 +567,8 @@ void cmState::SetGlobalProperty(const std::string& prop, const char* value) this->GlobalProperties.SetProperty(prop, value); } -void cmState::AppendGlobalProperty(const std::string& prop, const char* value, - bool asString) +void cmState::AppendGlobalProperty(const std::string& prop, + const std::string& value, bool asString) { this->GlobalProperties.AppendProperty(prop, value, asString); } @@ -615,6 +620,9 @@ const char* cmState::GetGlobalProperty(const std::string& prop) if (prop == "CMAKE_CXX14_KNOWN_FEATURES") { return &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1]; } + if (prop == "CMAKE_CUDA_KNOWN_FEATURES") { + return &FOR_EACH_CUDA_FEATURE(STRING_LIST_ELEMENT)[1]; + } #undef STRING_LIST_ELEMENT return this->GlobalProperties.GetPropertyValue(prop); @@ -712,6 +720,16 @@ bool cmState::UseMSYSShell() const return this->MSYSShell; } +void cmState::SetNinjaMulti(bool ninjaMulti) +{ + this->NinjaMulti = ninjaMulti; +} + +bool cmState::UseNinjaMulti() const +{ + return this->NinjaMulti; +} + unsigned int cmState::GetCacheMajorVersion() const { return this->CacheManager->GetCacheMajorVersion(); @@ -993,12 +1011,12 @@ bool cmState::ParseCacheEntry(const std::string& entry, std::string& var, bool flag = false; if (regQuoted.find(entry)) { var = regQuoted.match(1); - type = cmState::StringToCacheEntryType(regQuoted.match(2).c_str()); + type = cmState::StringToCacheEntryType(regQuoted.match(2)); value = regQuoted.match(3); flag = true; } else if (reg.find(entry)) { var = reg.match(1); - type = cmState::StringToCacheEntryType(reg.match(2).c_str()); + type = cmState::StringToCacheEntryType(reg.match(2)); value = reg.match(3); flag = true; } diff --git a/Source/cmState.h b/Source/cmState.h index a7ca015..6ee2b0c 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -70,10 +70,12 @@ public: cmStateSnapshot const& originSnapshot); cmStateSnapshot Pop(cmStateSnapshot const& originSnapshot); - static cmStateEnums::CacheEntryType StringToCacheEntryType(const char*); - static bool StringToCacheEntryType(const char*, + static cmStateEnums::CacheEntryType StringToCacheEntryType( + const std::string&); + static bool StringToCacheEntryType(const std::string&, cmStateEnums::CacheEntryType& type); - static const char* CacheEntryTypeToString(cmStateEnums::CacheEntryType); + static const std::string& CacheEntryTypeToString( + cmStateEnums::CacheEntryType); static bool IsCacheEntryType(std::string const& key); bool LoadCache(const std::string& path, bool internal, @@ -86,6 +88,7 @@ public: std::vector<std::string> GetCacheEntryKeys() const; const char* GetCacheEntryValue(std::string const& key) const; + std::string GetSafeCacheEntryValue(std::string const& key) const; const std::string* GetInitializedCacheValue(std::string const& key) const; cmStateEnums::CacheEntryType GetCacheEntryType(std::string const& key) const; void SetCacheEntryValue(std::string const& key, std::string const& value); @@ -166,7 +169,7 @@ public: std::vector<std::string> GetCommandNames() const; void SetGlobalProperty(const std::string& prop, const char* value); - void AppendGlobalProperty(const std::string& prop, const char* value, + void AppendGlobalProperty(const std::string& prop, const std::string& value, bool asString = false); const char* GetGlobalProperty(const std::string& prop); bool GetGlobalPropertyAsBool(const std::string& prop); @@ -190,6 +193,8 @@ public: bool UseNMake() const; void SetMSYSShell(bool mSYSShell); bool UseMSYSShell() const; + void SetNinjaMulti(bool ninjaMulti); + bool UseNinjaMulti() const; unsigned int GetCacheMajorVersion() const; unsigned int GetCacheMinorVersion() const; @@ -245,6 +250,7 @@ private: bool MinGWMake = false; bool NMake = false; bool MSYSShell = false; + bool NinjaMulti = false; Mode CurrentMode = Unknown; }; diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx index 1262f53..4f003ed 100644 --- a/Source/cmStateDirectory.cxx +++ b/Source/cmStateDirectory.cxx @@ -8,6 +8,7 @@ #include <vector> #include <cm/iterator> +#include <cmext/algorithm> #include "cmAlgorithms.h" #include "cmProperty.h" @@ -520,7 +521,7 @@ void cmStateDirectory::SetProperty(const std::string& prop, const char* value, } void cmStateDirectory::AppendProperty(const std::string& prop, - const char* value, bool asString, + const std::string& value, bool asString, cmListFileBacktrace const& lfbt) { if (prop == "INCLUDE_DIRECTORIES") { @@ -607,7 +608,7 @@ const char* cmStateDirectory::GetProperty(const std::string& prop, } if (prop == "VARIABLES") { std::vector<std::string> res = this->Snapshot_.ClosureKeys(); - cmAppend(res, this->Snapshot_.State->GetCacheEntryKeys()); + cm::append(res, this->Snapshot_.State->GetCacheEntryKeys()); std::sort(res.begin(), res.end()); output = cmJoin(res, ";"); return output.c_str(); diff --git a/Source/cmStateDirectory.h b/Source/cmStateDirectory.h index fe15563..53a2d54 100644 --- a/Source/cmStateDirectory.h +++ b/Source/cmStateDirectory.h @@ -84,7 +84,7 @@ public: void SetProperty(const std::string& prop, const char* value, cmListFileBacktrace const& lfbt); - void AppendProperty(const std::string& prop, const char* value, + void AppendProperty(const std::string& prop, const std::string& value, bool asString, cmListFileBacktrace const& lfbt); const char* GetProperty(const std::string& prop) const; const char* GetProperty(const std::string& prop, bool chain) const; diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx index 645907c..832e74e 100644 --- a/Source/cmStateSnapshot.cxx +++ b/Source/cmStateSnapshot.cxx @@ -315,10 +315,14 @@ void cmStateSnapshot::SetDefaultDefinitions() this->SetDefinition("UNIX", "1"); this->SetDefinition("CMAKE_HOST_UNIX", "1"); +# if defined(__ANDROID__) + this->SetDefinition("CMAKE_HOST_SYSTEM_NAME", "Android"); +# else struct utsname uts_name; if (uname(&uts_name) >= 0) { this->SetDefinition("CMAKE_HOST_SYSTEM_NAME", uts_name.sysname); } +# endif #endif #if defined(__CYGWIN__) std::string legacy; diff --git a/Source/cmString.hxx b/Source/cmString.hxx index 073f4c9..9e91986 100644 --- a/Source/cmString.hxx +++ b/Source/cmString.hxx @@ -88,18 +88,6 @@ struct IntoString<std::string> : std::true_type }; template <> -struct IntoString<string_view> : std::true_type -{ - static std::string into_string(string_view s) { return std::string(s); } -}; - -template <> -struct IntoString<static_string_view> : std::true_type -{ - static string_view into_string(static_string_view s) { return s; } -}; - -template <> struct IntoString<char> : std::true_type { static std::string into_string(char const& c) { return std::string(1, c); } @@ -239,6 +227,25 @@ public: { } + /** + * Construct via static_string_view constructor. + * explicit is required to avoid ambiguous overloaded operators (i.e ==, + * etc...) with the ones provided by string_view. + */ + explicit String(static_string_view s) + : String(s, Private()) + { + } + /** + * Construct via string_view constructor. + * explicit is required to avoid ambiguous overloaded operators (i.e ==, + * etc...) with the ones provided by string_view. + */ + explicit String(string_view s) + : String(std::string(s), Private()) + { + } + /** Construct via std::string initializer list constructor. */ String(std::initializer_list<char> il) : String(std::string(il)) @@ -306,6 +313,17 @@ public: This shares ownership of the other string's buffer. */ String& operator=(String const&) noexcept = default; + String& operator=(static_string_view s) + { + *this = String(s); + return *this; + } + String& operator=(string_view s) + { + *this = String(s); + return *this; + } + /** Assign from any type implementing the IntoString trait. */ template <typename T> typename // NOLINT(*) @@ -328,6 +346,7 @@ public: /** Return a view of the string. */ string_view view() const noexcept { return view_; } + operator string_view() const noexcept { return this->view(); } /** Return true if the instance is an empty stringn or null string. */ bool empty() const noexcept { return view_.empty(); } @@ -638,58 +657,155 @@ private: string_view view_; }; -template <typename L, typename R> -typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value, - bool>::type -operator==(L&& l, R&& r) +/** + * Trait for comparable types. + */ +template <typename T> +struct IsComparable : std::false_type +{ +}; + +template <typename T> +struct IsComparable<T&> : IsComparable<T> +{ +}; + +template <typename T> +struct IsComparable<T const> : IsComparable<T> +{ +}; + +template <typename T> +struct IsComparable<T const*> : IsComparable<T*> +{ +}; + +template <typename T, std::string::size_type N> +struct IsComparable<T const[N]> : IsComparable<T[N]> +{ +}; + +template <> +struct IsComparable<char*> : std::true_type { - return (AsStringView<L>::view(std::forward<L>(l)) == - AsStringView<R>::view(std::forward<R>(r))); +}; + +template <std::string::size_type N> +struct IsComparable<char[N]> : std::true_type +{ +}; + +template <> +struct IsComparable<std::string> : std::true_type +{ +}; + +template <> +struct IsComparable<char> : std::true_type +{ +}; + +/** comparison operators */ +inline bool operator==(const String& l, const String& r) +{ + return l.view() == r.view(); +} +template <typename L> +typename std::enable_if<IsComparable<L>::value, bool>::type operator==( + L&& l, const String& r) +{ + return AsStringView<L>::view(std::forward<L>(l)) == r.view(); +} +template <typename R> +typename std::enable_if<IsComparable<R>::value, bool>::type operator==( + const String& l, R&& r) +{ + return l.view() == AsStringView<R>::view(std::forward<R>(r)); } -template <typename L, typename R> -typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value, - bool>::type -operator!=(L&& l, R&& r) +inline bool operator!=(const String& l, const String& r) +{ + return l.view() != r.view(); +} +template <typename L> +typename std::enable_if<IsComparable<L>::value, bool>::type operator!=( + L&& l, const String& r) { - return (AsStringView<L>::view(std::forward<L>(l)) != - AsStringView<R>::view(std::forward<R>(r))); + return AsStringView<L>::view(std::forward<L>(l)) != r.view(); +} +template <typename R> +typename std::enable_if<IsComparable<R>::value, bool>::type operator!=( + const String& l, R&& r) +{ + return l.view() != AsStringView<R>::view(std::forward<R>(r)); } -template <typename L, typename R> -typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value, - bool>::type -operator<(L&& l, R&& r) +inline bool operator<(const String& l, const String& r) { - return (AsStringView<L>::view(std::forward<L>(l)) < - AsStringView<R>::view(std::forward<R>(r))); + return l.view() < r.view(); +} +template <typename L> +typename std::enable_if<IsComparable<L>::value, bool>::type operator<( + L&& l, const String& r) +{ + return AsStringView<L>::view(std::forward<L>(l)) < r.view(); +} +template <typename R> +typename std::enable_if<IsComparable<R>::value, bool>::type operator<( + const String& l, R&& r) +{ + return l.view() < AsStringView<R>::view(std::forward<R>(r)); } -template <typename L, typename R> -typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value, - bool>::type -operator<=(L&& l, R&& r) +inline bool operator<=(const String& l, const String& r) +{ + return l.view() <= r.view(); +} +template <typename L> +typename std::enable_if<IsComparable<L>::value, bool>::type operator<=( + L&& l, const String& r) +{ + return AsStringView<L>::view(std::forward<L>(l)) <= r.view(); +} +template <typename R> +typename std::enable_if<IsComparable<R>::value, bool>::type operator<=( + const String& l, R&& r) { - return (AsStringView<L>::view(std::forward<L>(l)) <= - AsStringView<R>::view(std::forward<R>(r))); + return l.view() <= AsStringView<R>::view(std::forward<R>(r)); } -template <typename L, typename R> -typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value, - bool>::type -operator>(L&& l, R&& r) +inline bool operator>(const String& l, const String& r) +{ + return l.view() > r.view(); +} +template <typename L> +typename std::enable_if<IsComparable<L>::value, bool>::type operator>( + L&& l, const String& r) +{ + return AsStringView<L>::view(std::forward<L>(l)) > r.view(); +} +template <typename R> +typename std::enable_if<IsComparable<R>::value, bool>::type operator>( + const String& l, R&& r) { - return (AsStringView<L>::view(std::forward<L>(l)) > - AsStringView<R>::view(std::forward<R>(r))); + return l.view() > AsStringView<R>::view(std::forward<R>(r)); } -template <typename L, typename R> -typename std::enable_if<AsStringView<L>::value && AsStringView<R>::value, - bool>::type -operator>=(L&& l, R&& r) +inline bool operator>=(const String& l, const String& r) +{ + return l.view() >= r.view(); +} +template <typename L> +typename std::enable_if<IsComparable<L>::value, bool>::type operator>=( + L&& l, const String& r) +{ + return AsStringView<L>::view(std::forward<L>(l)) >= r.view(); +} +template <typename R> +typename std::enable_if<IsComparable<R>::value, bool>::type operator>=( + const String& l, R&& r) { - return (AsStringView<L>::view(std::forward<L>(l)) >= - AsStringView<R>::view(std::forward<R>(r))); + return l.view() >= AsStringView<R>::view(std::forward<R>(r)); } std::ostream& operator<<(std::ostream& os, String const& s); diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 9212195..7662204 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -124,6 +124,27 @@ bool HandleAsciiCommand(std::vector<std::string> const& args, return true; } +bool HandleHexCommand(std::vector<std::string> const& args, + cmExecutionStatus& status) +{ + if (args.size() != 3) { + status.SetError("Incorrect number of arguments"); + return false; + } + auto const& instr = args[1]; + auto const& outvar = args[2]; + std::string output(instr.size() * 2, ' '); + + std::string::size_type hexIndex = 0; + for (auto const& c : instr) { + sprintf(&output[hexIndex], "%.2x", static_cast<unsigned char>(c) & 0xFF); + hexIndex += 2; + } + + status.GetMakefile().AddDefinition(outvar, output); + return true; +} + bool HandleConfigureCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -936,6 +957,7 @@ bool cmStringCommand(std::vector<std::string> const& args, { "TOUPPER"_s, HandleToUpperCommand }, { "COMPARE"_s, HandleCompareCommand }, { "ASCII"_s, HandleAsciiCommand }, + { "HEX"_s, HandleHexCommand }, { "CONFIGURE"_s, HandleConfigureCommand }, { "LENGTH"_s, HandleLengthCommand }, { "APPEND"_s, HandleAppendCommand }, diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index c4a4220..d8cd705 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2,9 +2,10 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmSystemTools.h" +#include <cmext/algorithm> + #include "cm_uv.h" -#include "cmAlgorithms.h" #include "cmDuration.h" #include "cmProcessOutput.h" #include "cmRange.h" @@ -24,6 +25,9 @@ #endif #if !defined(CMAKE_BOOTSTRAP) +# if defined(_WIN32) +# include <cm/memory> +# endif # include "cmCryptoHash.h" #endif @@ -360,7 +364,7 @@ std::vector<std::string> cmSystemTools::HandleResponseFile( #else cmSystemTools::ParseUnixCommandLine(line.c_str(), args2); #endif - cmAppend(arg_full, args2); + cm::append(arg_full, args2); } } else { arg_full.push_back(arg); @@ -585,7 +589,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command, cmSystemTools::Stdout(strdata); } if (captureStdOut) { - cmAppend(tempStdOut, data, data + length); + cm::append(tempStdOut, data, data + length); } } else if (pipe == cmsysProcess_Pipe_STDERR) { if (outputflag != OUTPUT_NONE) { @@ -593,7 +597,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command, cmSystemTools::Stderr(strdata); } if (captureStdErr) { - cmAppend(tempStdErr, data, data + length); + cm::append(tempStdErr, data, data + length); } } } @@ -814,6 +818,8 @@ void cmSystemTools::InitializeLibUV() # else _fmode = _O_TEXT; # endif + // Replace libuv's report handler with our own to suppress popups. + cmSystemTools::EnableMSVCDebugHook(); #endif } @@ -905,7 +911,6 @@ std::string cmSystemTools::ComputeCertificateThumbprint( std::string thumbprint; #if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32) - BYTE* certData = NULL; CRYPT_INTEGER_BLOB cryptBlob; HCERTSTORE certStore = NULL; PCCERT_CONTEXT certContext = NULL; @@ -917,12 +922,12 @@ std::string cmSystemTools::ComputeCertificateThumbprint( if (certFile != INVALID_HANDLE_VALUE && certFile != NULL) { DWORD fileSize = GetFileSize(certFile, NULL); if (fileSize != INVALID_FILE_SIZE) { - certData = new BYTE[fileSize]; + auto certData = cm::make_unique<BYTE[]>(fileSize); if (certData != NULL) { DWORD dwRead = 0; - if (ReadFile(certFile, certData, fileSize, &dwRead, NULL)) { + if (ReadFile(certFile, certData.get(), fileSize, &dwRead, NULL)) { cryptBlob.cbData = fileSize; - cryptBlob.pbData = certData; + cryptBlob.pbData = certData.get(); // Verify that this is a valid cert if (PFXIsPFXBlob(&cryptBlob)) { @@ -958,7 +963,6 @@ std::string cmSystemTools::ComputeCertificateThumbprint( } } } - delete[] certData; } } CloseHandle(certFile); @@ -1710,26 +1714,26 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line, processOutput.DecodeText(data, length, strdata, 1); // Append to the stdout buffer. std::vector<char>::size_type size = out.size(); - cmAppend(out, strdata); + cm::append(out, strdata); outiter = out.begin() + size; } else if (pipe == cmsysProcess_Pipe_STDERR) { processOutput.DecodeText(data, length, strdata, 2); // Append to the stderr buffer. std::vector<char>::size_type size = err.size(); - cmAppend(err, strdata); + cm::append(err, strdata); erriter = err.begin() + size; } else if (pipe == cmsysProcess_Pipe_None) { // Both stdout and stderr pipes have broken. Return leftover data. processOutput.DecodeText(std::string(), strdata, 1); if (!strdata.empty()) { std::vector<char>::size_type size = out.size(); - cmAppend(out, strdata); + cm::append(out, strdata); outiter = out.begin() + size; } processOutput.DecodeText(std::string(), strdata, 2); if (!strdata.empty()) { std::vector<char>::size_type size = err.size(); - cmAppend(err, strdata); + cm::append(err, strdata); erriter = err.begin() + size; } if (!out.empty()) { diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 80986fc..10515c2 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -12,6 +12,7 @@ #include <unordered_set> #include <cm/memory> +#include <cmext/algorithm> #include "cmsys/RegularExpression.hxx" @@ -38,13 +39,13 @@ #include "cmake.h" template <> -const char* cmTargetPropertyComputer::ComputeLocationForBuild<cmTarget>( +const std::string& cmTargetPropertyComputer::ComputeLocationForBuild<cmTarget>( cmTarget const* tgt) { static std::string loc; if (tgt->IsImported()) { loc = tgt->ImportedGetFullPath("", cmStateEnums::RuntimeBinaryArtifact); - return loc.c_str(); + return loc; } cmGlobalGenerator* gg = tgt->GetGlobalGenerator(); @@ -53,18 +54,18 @@ const char* cmTargetPropertyComputer::ComputeLocationForBuild<cmTarget>( } cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName()); loc = gt->GetLocationForBuild(); - return loc.c_str(); + return loc; } template <> -const char* cmTargetPropertyComputer::ComputeLocation<cmTarget>( +const std::string& cmTargetPropertyComputer::ComputeLocation<cmTarget>( cmTarget const* tgt, const std::string& config) { static std::string loc; if (tgt->IsImported()) { loc = tgt->ImportedGetFullPath(config, cmStateEnums::RuntimeBinaryArtifact); - return loc.c_str(); + return loc; } cmGlobalGenerator* gg = tgt->GetGlobalGenerator(); @@ -73,7 +74,7 @@ const char* cmTargetPropertyComputer::ComputeLocation<cmTarget>( } cmGeneratorTarget* gt = gg->FindGeneratorTarget(tgt->GetName()); loc = gt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact); - return loc.c_str(); + return loc; } template <> @@ -176,7 +177,8 @@ public: bool IsImportedTarget; bool ImportedGloballyVisible; bool BuildInterfaceIncludesAppended; - std::set<BT<std::string>> Utilities; + bool PerConfig; + std::set<BT<std::pair<std::string, bool>>> Utilities; std::vector<cmCustomCommand> PreBuildCommands; std::vector<cmCustomCommand> PreLinkCommands; std::vector<cmCustomCommand> PostBuildCommands; @@ -213,7 +215,7 @@ public: }; cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, - Visibility vis, cmMakefile* mf) + Visibility vis, cmMakefile* mf, bool perConfig) : impl(cm::make_unique<cmTargetInternals>()) { assert(mf); @@ -229,6 +231,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, (vis == VisibilityImported || vis == VisibilityImportedGlobally); impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally; impl->BuildInterfaceIncludesAppended = false; + impl->PerConfig = perConfig; // Check whether this is a DLL platform. impl->IsDLLPlatform = @@ -297,6 +300,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("PDB_OUTPUT_DIRECTORY"); initProp("COMPILE_PDB_OUTPUT_DIRECTORY"); initProp("FRAMEWORK"); + initProp("FRAMEWORK_MULTI_CONFIG_POSTFIX"); initProp("Fortran_FORMAT"); initProp("Fortran_MODULE_DIRECTORY"); initProp("Fortran_COMPILER_LAUNCHER"); @@ -355,9 +359,9 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("CUDA_COMPILER_LAUNCHER"); initProp("CUDA_SEPARABLE_COMPILATION"); initProp("CUDA_RESOLVE_DEVICE_SYMBOLS"); + initProp("CUDA_RUNTIME_LIBRARY"); initProp("LINK_SEARCH_START_STATIC"); initProp("LINK_SEARCH_END_STATIC"); - initProp("FOLDER"); initProp("Swift_LANGUAGE_VERSION"); initProp("Swift_MODULE_DIRECTORY"); initProp("VS_JUST_MY_CODE_DEBUGGING"); @@ -373,6 +377,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("XCODE_SCHEME_THREAD_SANITIZER_STOP"); initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER"); initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP"); + initProp("XCODE_SCHEME_WORKING_DIRECTORY"); initProp("XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER"); initProp("XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP"); initProp("XCODE_SCHEME_MALLOC_SCRIBBLE"); @@ -382,11 +387,14 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("XCODE_SCHEME_MALLOC_STACK"); initProp("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE"); initProp("XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS"); + initProp("XCODE_SCHEME_ENVIRONMENT"); } #endif } if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { + initProp("FOLDER"); + if (this->GetGlobalGenerator()->IsXcode()) { initProp("XCODE_GENERATE_SCHEME"); } @@ -428,6 +436,13 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, cmStrCat(cmSystemTools::UpperCase(configName), "_POSTFIX"); initProp(property); } + + if (impl->TargetType == cmStateEnums::SHARED_LIBRARY || + impl->TargetType == cmStateEnums::STATIC_LIBRARY) { + std::string property = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_", + cmSystemTools::UpperCase(configName)); + initProp(property); + } } } @@ -437,30 +452,30 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, if (!this->IsImported()) { // Initialize the INCLUDE_DIRECTORIES property based on the current value // of the same directory property: - cmAppend(impl->IncludeDirectoriesEntries, - impl->Makefile->GetIncludeDirectoriesEntries()); - cmAppend(impl->IncludeDirectoriesBacktraces, - impl->Makefile->GetIncludeDirectoriesBacktraces()); + cm::append(impl->IncludeDirectoriesEntries, + impl->Makefile->GetIncludeDirectoriesEntries()); + cm::append(impl->IncludeDirectoriesBacktraces, + impl->Makefile->GetIncludeDirectoriesBacktraces()); { auto const& sysInc = impl->Makefile->GetSystemIncludeDirectories(); impl->SystemIncludeDirectories.insert(sysInc.begin(), sysInc.end()); } - cmAppend(impl->CompileOptionsEntries, - impl->Makefile->GetCompileOptionsEntries()); - cmAppend(impl->CompileOptionsBacktraces, - impl->Makefile->GetCompileOptionsBacktraces()); + cm::append(impl->CompileOptionsEntries, + impl->Makefile->GetCompileOptionsEntries()); + cm::append(impl->CompileOptionsBacktraces, + impl->Makefile->GetCompileOptionsBacktraces()); - cmAppend(impl->LinkOptionsEntries, - impl->Makefile->GetLinkOptionsEntries()); - cmAppend(impl->LinkOptionsBacktraces, - impl->Makefile->GetLinkOptionsBacktraces()); + cm::append(impl->LinkOptionsEntries, + impl->Makefile->GetLinkOptionsEntries()); + cm::append(impl->LinkOptionsBacktraces, + impl->Makefile->GetLinkOptionsBacktraces()); - cmAppend(impl->LinkDirectoriesEntries, - impl->Makefile->GetLinkDirectoriesEntries()); - cmAppend(impl->LinkDirectoriesBacktraces, - impl->Makefile->GetLinkDirectoriesBacktraces()); + cm::append(impl->LinkDirectoriesEntries, + impl->Makefile->GetLinkDirectoriesEntries()); + cm::append(impl->LinkDirectoriesBacktraces, + impl->Makefile->GetLinkDirectoriesBacktraces()); } if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && @@ -484,6 +499,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, } if (impl->TargetType == cmStateEnums::SHARED_LIBRARY || impl->TargetType == cmStateEnums::EXECUTABLE) { + initProp("AIX_EXPORT_ALL_SYMBOLS"); initProp("WINDOWS_EXPORT_ALL_SYMBOLS"); } @@ -507,14 +523,15 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->GetType() != cmStateEnums::UTILITY) { initProp("JOB_POOL_COMPILE"); initProp("JOB_POOL_LINK"); + initProp("JOB_POOL_PRECOMPILE_HEADER"); } if (impl->TargetType <= cmStateEnums::UTILITY) { + initProp("DOTNET_TARGET_FRAMEWORK"); initProp("DOTNET_TARGET_FRAMEWORK_VERSION"); } - if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && - this->GetType() != cmStateEnums::UTILITY) { + if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { // check for "CMAKE_VS_GLOBALS" variable and set up target properties // if any @@ -574,13 +591,14 @@ cmGlobalGenerator* cmTarget::GetGlobalGenerator() const return impl->Makefile->GetGlobalGenerator(); } -void cmTarget::AddUtility(std::string const& name, cmMakefile* mf) +void cmTarget::AddUtility(std::string const& name, bool cross, cmMakefile* mf) { - impl->Utilities.insert( - BT<std::string>(name, mf ? mf->GetBacktrace() : cmListFileBacktrace())); + impl->Utilities.insert(BT<std::pair<std::string, bool>>( + { name, cross }, mf ? mf->GetBacktrace() : cmListFileBacktrace())); } -std::set<BT<std::string>> const& cmTarget::GetUtilities() const +std::set<BT<std::pair<std::string, bool>>> const& cmTarget::GetUtilities() + const { return impl->Utilities; } @@ -932,14 +950,7 @@ cmTarget::LinkLibraryVectorType const& cmTarget::GetOriginalLinkLibraries() return impl->OriginalLinkLibraries; } -void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib, - cmTargetLinkLibraryType llt) -{ - this->AddLinkLibrary(mf, lib, lib, llt); -} - void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib, - std::string const& libRef, cmTargetLinkLibraryType llt) { cmTarget* tgt = mf.FindTargetToUse(lib); @@ -948,14 +959,13 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib, const std::string libName = (isNonImportedTarget && llt != GENERAL_LibraryType) - ? targetNameGenex(libRef) - : libRef; - this->AppendProperty( - "LINK_LIBRARIES", - this->GetDebugGeneratorExpressions(libName, llt).c_str()); + ? targetNameGenex(lib) + : lib; + this->AppendProperty("LINK_LIBRARIES", + this->GetDebugGeneratorExpressions(libName, llt)); } - if (cmGeneratorExpression::Find(lib) != std::string::npos || lib != libRef || + if (cmGeneratorExpression::Find(lib) != std::string::npos || (tgt && (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY || tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) || @@ -997,7 +1007,7 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib, dependencies += ";"; dependencies += lib; dependencies += ";"; - mf.AddCacheDefinition(targetEntry, dependencies.c_str(), + mf.AddCacheDefinition(targetEntry, dependencies, "Dependencies for the target", cmStateEnums::STATIC); } } @@ -1286,20 +1296,20 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) impl->Properties.SetProperty(prop, reusedFrom.c_str()); - reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom.c_str()); + reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom); reusedTarget->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY", - cmStrCat(reusedFrom, ".dir/").c_str()); + cmStrCat(reusedFrom, ".dir/")); this->SetProperty("COMPILE_PDB_NAME", reusedTarget->GetProperty("COMPILE_PDB_NAME")); - this->AddUtility(reusedFrom, impl->Makefile); + this->AddUtility(reusedFrom, false, impl->Makefile); } else { impl->Properties.SetProperty(prop, value); } } -void cmTarget::AppendProperty(const std::string& prop, const char* value, - bool asString) +void cmTarget::AppendProperty(const std::string& prop, + const std::string& value, bool asString) { if (!cmTargetPropertyComputer::PassesWhitelist( this->GetType(), prop, impl->Makefile->GetMessenger(), @@ -1334,37 +1344,37 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value, return; } if (prop == "INCLUDE_DIRECTORIES") { - if (value && *value) { + if (!value.empty()) { impl->IncludeDirectoriesEntries.emplace_back(value); cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); impl->IncludeDirectoriesBacktraces.push_back(lfbt); } } else if (prop == "COMPILE_OPTIONS") { - if (value && *value) { + if (!value.empty()) { impl->CompileOptionsEntries.emplace_back(value); cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); impl->CompileOptionsBacktraces.push_back(lfbt); } } else if (prop == "COMPILE_FEATURES") { - if (value && *value) { + if (!value.empty()) { impl->CompileFeaturesEntries.emplace_back(value); cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); impl->CompileFeaturesBacktraces.push_back(lfbt); } } else if (prop == "COMPILE_DEFINITIONS") { - if (value && *value) { + if (!value.empty()) { impl->CompileDefinitionsEntries.emplace_back(value); cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); impl->CompileDefinitionsBacktraces.push_back(lfbt); } } else if (prop == "LINK_OPTIONS") { - if (value && *value) { + if (!value.empty()) { impl->LinkOptionsEntries.emplace_back(value); cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); impl->LinkOptionsBacktraces.push_back(lfbt); } } else if (prop == "LINK_DIRECTORIES") { - if (value && *value) { + if (!value.empty()) { impl->LinkDirectoriesEntries.emplace_back(value); cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); impl->LinkDirectoriesBacktraces.push_back(lfbt); @@ -1378,13 +1388,13 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value, impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } - if (value && *value) { + if (!value.empty()) { impl->PrecompileHeadersEntries.emplace_back(value); cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); impl->PrecompileHeadersBacktraces.push_back(lfbt); } } else if (prop == "LINK_LIBRARIES") { - if (value && *value) { + if (!value.empty()) { cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); impl->LinkImplementationPropertyEntries.emplace_back(value); impl->LinkImplementationPropertyBacktraces.push_back(lfbt); @@ -1423,7 +1433,7 @@ void cmTarget::AppendBuildInterfaceIncludes() dirs += impl->Makefile->GetCurrentSourceDirectory(); if (!dirs.empty()) { this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES", - ("$<BUILD_INTERFACE:" + dirs + ">").c_str()); + ("$<BUILD_INTERFACE:" + dirs + ">")); } } } @@ -1558,8 +1568,12 @@ static void cmTargetCheckINTERFACE_LINK_LIBRARIES(const char* value, static void cmTargetCheckIMPORTED_GLOBAL(const cmTarget* target, cmMakefile* context) { - std::vector<cmTarget*> targets = context->GetOwnedImportedTargets(); - auto it = std::find(targets.begin(), targets.end(), target); + const auto& targets = context->GetOwnedImportedTargets(); + auto it = + std::find_if(targets.begin(), targets.end(), + [&](const std::unique_ptr<cmTarget>& importTarget) -> bool { + return target == importTarget.get(); + }); if (it == targets.end()) { std::ostringstream e; e << "Attempt to promote imported target \"" << target->GetName() @@ -1715,7 +1729,14 @@ const char* cmTarget::GetProperty(const std::string& prop) const } static std::string output; - output = cmJoin(impl->Utilities, ";"); + static std::vector<std::string> utilities; + utilities.resize(impl->Utilities.size()); + std::transform( + impl->Utilities.cbegin(), impl->Utilities.cend(), utilities.begin(), + [](const BT<std::pair<std::string, bool>>& item) -> std::string { + return item.Value.first; + }); + output = cmJoin(utilities, ";"); return output.c_str(); } if (prop == propPRECOMPILE_HEADERS) { @@ -1801,6 +1822,11 @@ bool cmTarget::IsImportedGloballyVisible() const return impl->ImportedGloballyVisible; } +bool cmTarget::IsPerConfig() const +{ + return impl->PerConfig; +} + const char* cmTarget::GetSuffixVariableInternal( cmStateEnums::ArtifactType artifact) const { diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 65a1ce3..286933b 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -44,7 +44,7 @@ public: }; cmTarget(std::string const& name, cmStateEnums::TargetType type, - Visibility vis, cmMakefile* mf); + Visibility vis, cmMakefile* mf, bool perConfig); cmTarget(cmTarget const&) = delete; cmTarget(cmTarget&&) noexcept; @@ -110,10 +110,8 @@ public: //! Clear the dependency information recorded for this target, if any. void ClearDependencyInformation(cmMakefile& mf); - void AddLinkLibrary(cmMakefile& mf, const std::string& lib, - cmTargetLinkLibraryType llt); void AddLinkLibrary(cmMakefile& mf, std::string const& lib, - std::string const& libRef, cmTargetLinkLibraryType llt); + cmTargetLinkLibraryType llt); enum TLLSignature { @@ -158,13 +156,18 @@ public: * name as would be specified to the ADD_EXECUTABLE or UTILITY_SOURCE * commands. It is not a full path nor does it have an extension. */ - void AddUtility(std::string const& name, cmMakefile* mf = nullptr); + void AddUtility(std::string const& name, bool cross, + cmMakefile* mf = nullptr); //! Get the utilities used by this target - std::set<BT<std::string>> const& GetUtilities() const; + std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const; //! Set/Get a property of this target file void SetProperty(const std::string& prop, const char* value); - void AppendProperty(const std::string& prop, const char* value, + void SetProperty(const std::string& prop, const std::string& value) + { + SetProperty(prop, value.c_str()); + } + void AppendProperty(const std::string& prop, const std::string& value, bool asString = false); //! Might return a nullptr if the property is not set or invalid const char* GetProperty(const std::string& prop) const; @@ -186,6 +189,7 @@ public: bool IsImported() const; bool IsImportedGloballyVisible() const; + bool IsPerConfig() const; bool GetMappedConfig(std::string const& desired_config, const char** loc, const char** imp, std::string& suffix) const; diff --git a/Source/cmTargetCompileDefinitionsCommand.cxx b/Source/cmTargetCompileDefinitionsCommand.cxx index edee167..b56b245 100644 --- a/Source/cmTargetCompileDefinitionsCommand.cxx +++ b/Source/cmTargetCompileDefinitionsCommand.cxx @@ -28,7 +28,7 @@ private: const std::vector<std::string>& content, bool /*prepend*/, bool /*system*/) override { - tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content).c_str()); + tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content)); return true; // Successfully handled. } diff --git a/Source/cmTargetCompileOptionsCommand.cxx b/Source/cmTargetCompileOptionsCommand.cxx index e39b726..dee2c10 100644 --- a/Source/cmTargetCompileOptionsCommand.cxx +++ b/Source/cmTargetCompileOptionsCommand.cxx @@ -5,6 +5,7 @@ #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmPolicies.h" #include "cmStringAlgorithms.h" #include "cmTarget.h" #include "cmTargetPropCommandBase.h" @@ -27,10 +28,16 @@ private: bool HandleDirectContent(cmTarget* tgt, const std::vector<std::string>& content, - bool /*prepend*/, bool /*system*/) override + bool prepend, bool /*system*/) override { + cmPolicies::PolicyStatus policyStatus = + this->Makefile->GetPolicyStatus(cmPolicies::CMP0101); + if (policyStatus == cmPolicies::OLD || policyStatus == cmPolicies::WARN) { + prepend = false; + } + cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - tgt->InsertCompileOption(this->Join(content), lfbt); + tgt->InsertCompileOption(this->Join(content), lfbt, prepend); return true; // Successfully handled. } diff --git a/Source/cmTargetDepend.h b/Source/cmTargetDepend.h index 4ca78fa..5452cc7 100644 --- a/Source/cmTargetDepend.h +++ b/Source/cmTargetDepend.h @@ -19,6 +19,7 @@ class cmTargetDepend // mutable members to achieve a map with set syntax. mutable bool Link; mutable bool Util; + mutable bool Cross; mutable cmListFileBacktrace Backtrace; public: @@ -26,6 +27,7 @@ public: : Target(t) , Link(false) , Util(false) + , Cross(false) { } operator cmGeneratorTarget const*() const { return this->Target; } @@ -43,12 +45,14 @@ public: this->Link = true; } } + void SetCross(bool cross) const { this->Cross = cross; } void SetBacktrace(cmListFileBacktrace const& bt) const { this->Backtrace = bt; } bool IsLink() const { return this->Link; } bool IsUtil() const { return this->Util; } + bool IsCross() const { return this->Cross; } cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; } }; diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx index 95b69f3..35635b9 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.cxx +++ b/Source/cmTargetIncludeDirectoriesCommand.cxx @@ -88,8 +88,7 @@ void TargetIncludeDirectoriesImpl::HandleInterfaceContent( system); if (system) { std::string joined = this->Join(content); - tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", - joined.c_str()); + tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", joined); } } diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 0d2383a..df751da 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -3,7 +3,10 @@ #include "cmTargetLinkLibrariesCommand.h" #include <cstring> +#include <memory> #include <sstream> +#include <unordered_set> +#include <utility> #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" @@ -34,15 +37,30 @@ enum ProcessingState const char* LinkLibraryTypeNames[3] = { "general", "debug", "optimized" }; +struct TLL +{ + cmMakefile& Makefile; + cmTarget* Target; + bool WarnRemoteInterface = false; + bool RejectRemoteLinking = false; + bool EncodeRemoteReference = false; + std::string DirectoryId; + std::unordered_set<std::string> Props; + + TLL(cmMakefile& mf, cmTarget* target); + ~TLL(); + + bool HandleLibrary(ProcessingState currentProcessingState, + const std::string& lib, cmTargetLinkLibraryType llt); + void AppendProperty(std::string const& prop, std::string const& value); + void AffectsProperty(std::string const& prop); +}; + } // namespace static void LinkLibraryTypeSpecifierWarning(cmMakefile& mf, int left, int right); -static bool HandleLibrary(cmMakefile& mf, cmTarget* target, - ProcessingState currentProcessingState, - const std::string& lib, cmTargetLinkLibraryType llt); - bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -64,11 +82,9 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args, cmTarget* target = mf.GetCMakeInstance()->GetGlobalGenerator()->FindTarget(args[0]); if (!target) { - const std::vector<cmTarget*>& importedTargets = - mf.GetOwnedImportedTargets(); - for (cmTarget* importedTarget : importedTargets) { + for (const auto& importedTarget : mf.GetOwnedImportedTargets()) { if (importedTarget->GetName() == args[0]) { - target = importedTarget; + target = importedTarget.get(); break; } } @@ -149,6 +165,8 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args, return true; } + TLL tll(mf, target); + // Keep track of link configuration specifiers. cmTargetLinkLibraryType llt = GENERAL_LibraryType; bool haveLLT = false; @@ -247,7 +265,7 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args, } else if (haveLLT) { // The link type was specified by the previous argument. haveLLT = false; - if (!HandleLibrary(mf, target, currentProcessingState, args[i], llt)) { + if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) { return false; } } else { @@ -268,7 +286,7 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args, llt = OPTIMIZED_LibraryType; } } - if (!HandleLibrary(mf, target, currentProcessingState, args[i], llt)) { + if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) { return false; } } @@ -311,21 +329,48 @@ static void LinkLibraryTypeSpecifierWarning(cmMakefile& mf, int left, "\" instead of a library name. The first specifier will be ignored.")); } -static bool HandleLibrary(cmMakefile& mf, cmTarget* target, - ProcessingState currentProcessingState, - const std::string& lib, cmTargetLinkLibraryType llt) +namespace { + +TLL::TLL(cmMakefile& mf, cmTarget* target) + : Makefile(mf) + , Target(target) +{ + if (&this->Makefile != this->Target->GetMakefile()) { + // The LHS target was created in another directory. + switch (this->Makefile.GetPolicyStatus(cmPolicies::CMP0079)) { + case cmPolicies::WARN: + this->WarnRemoteInterface = true; + CM_FALLTHROUGH; + case cmPolicies::OLD: + this->RejectRemoteLinking = true; + break; + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::NEW: + this->EncodeRemoteReference = true; + break; + } + } + if (this->EncodeRemoteReference) { + cmDirectoryId const dirId = this->Makefile.GetDirectoryId(); + this->DirectoryId = cmStrCat(CMAKE_DIRECTORY_ID_SEP, dirId.String); + } +} + +bool TLL::HandleLibrary(ProcessingState currentProcessingState, + const std::string& lib, cmTargetLinkLibraryType llt) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY && + if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY && currentProcessingState != ProcessingKeywordLinkInterface) { - mf.IssueMessage( + this->Makefile.IssueMessage( MessageType::FATAL_ERROR, "INTERFACE library can only be used with the INTERFACE keyword of " "target_link_libraries"); return false; } - if (target->IsImported() && + if (this->Target->IsImported() && currentProcessingState != ProcessingKeywordLinkInterface) { - mf.IssueMessage( + this->Makefile.IssueMessage( MessageType::FATAL_ERROR, "IMPORTED library can only be used with the INTERFACE keyword of " "target_link_libraries"); @@ -340,11 +385,12 @@ static bool HandleLibrary(cmMakefile& mf, cmTarget* target, currentProcessingState == ProcessingKeywordLinkInterface) ? cmTarget::KeywordTLLSignature : cmTarget::PlainTLLSignature; - if (!target->PushTLLCommandTrace(sig, mf.GetExecutionContext())) { + if (!this->Target->PushTLLCommandTrace( + sig, this->Makefile.GetExecutionContext())) { std::ostringstream e; const char* modal = nullptr; MessageType messageType = MessageType::AUTHOR_WARNING; - switch (mf.GetPolicyStatus(cmPolicies::CMP0023)) { + switch (this->Makefile.GetPolicyStatus(cmPolicies::CMP0023)) { case cmPolicies::WARN: e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0023) << "\n"; modal = "should"; @@ -365,73 +411,38 @@ static bool HandleLibrary(cmMakefile& mf, cmTarget* target, e << "The " << existingSig << " signature for target_link_libraries has " "already been used with the target \"" - << target->GetName() + << this->Target->GetName() << "\". All uses of target_link_libraries with a target " << modal << " be either all-keyword or all-plain.\n"; - target->GetTllSignatureTraces(e, - sig == cmTarget::KeywordTLLSignature - ? cmTarget::PlainTLLSignature - : cmTarget::KeywordTLLSignature); - mf.IssueMessage(messageType, e.str()); + this->Target->GetTllSignatureTraces(e, + sig == cmTarget::KeywordTLLSignature + ? cmTarget::PlainTLLSignature + : cmTarget::KeywordTLLSignature); + this->Makefile.IssueMessage(messageType, e.str()); if (messageType == MessageType::FATAL_ERROR) { return false; } } } - bool warnRemoteInterface = false; - bool rejectRemoteLinking = false; - bool encodeRemoteReference = false; - if (&mf != target->GetMakefile()) { - // The LHS target was created in another directory. - switch (mf.GetPolicyStatus(cmPolicies::CMP0079)) { - case cmPolicies::WARN: - warnRemoteInterface = true; - CM_FALLTHROUGH; - case cmPolicies::OLD: - rejectRemoteLinking = true; - break; - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::NEW: - encodeRemoteReference = true; - break; - } - } - - std::string libRef; - if (encodeRemoteReference && !cmSystemTools::FileIsFullPath(lib)) { - // This is a library name added by a caller that is not in the - // same directory as the target was created. Add a suffix to - // the name to tell ResolveLinkItem to look up the name in the - // caller's directory. - cmDirectoryId const dirId = mf.GetDirectoryId(); - libRef = lib + CMAKE_DIRECTORY_ID_SEP + dirId.String; - } else { - // This is an absolute path or a library name added by a caller - // in the same directory as the target was created. We can use - // the original name directly. - libRef = lib; - } - // Handle normal case where the command was called with another keyword than // INTERFACE / LINK_INTERFACE_LIBRARIES or none at all. (The "LINK_LIBRARIES" // property of the target on the LHS shall be populated.) if (currentProcessingState != ProcessingKeywordLinkInterface && currentProcessingState != ProcessingPlainLinkInterface) { - if (rejectRemoteLinking) { - mf.IssueMessage( + if (this->RejectRemoteLinking) { + this->Makefile.IssueMessage( MessageType::FATAL_ERROR, cmStrCat("Attempt to add link library \"", lib, "\" to target \"", - target->GetName(), + this->Target->GetName(), "\" which is not built in this " "directory.\nThis is allowed only when policy CMP0079 " "is set to NEW.")); return false; } - cmTarget* tgt = mf.GetGlobalGenerator()->FindTarget(lib); + cmTarget* tgt = this->Makefile.GetGlobalGenerator()->FindTarget(lib); if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) && (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) && @@ -439,7 +450,7 @@ static bool HandleLibrary(cmMakefile& mf, cmTarget* target, (tgt->GetType() != cmStateEnums::OBJECT_LIBRARY) && (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) && !tgt->IsExecutableWithExports()) { - mf.IssueMessage( + this->Makefile.IssueMessage( MessageType::FATAL_ERROR, cmStrCat( "Target \"", lib, "\" of type ", @@ -449,15 +460,16 @@ static bool HandleLibrary(cmMakefile& mf, cmTarget* target, "executables with the ENABLE_EXPORTS property set.")); } - target->AddLinkLibrary(mf, lib, libRef, llt); + this->AffectsProperty("LINK_LIBRARIES"); + this->Target->AddLinkLibrary(this->Makefile, lib, llt); } - if (warnRemoteInterface) { - mf.IssueMessage( + if (this->WarnRemoteInterface) { + this->Makefile.IssueMessage( MessageType::AUTHOR_WARNING, cmStrCat( cmPolicies::GetPolicyWarning(cmPolicies::CMP0079), "\nTarget\n ", - target->GetName(), + this->Target->GetName(), "\nis not created in this " "directory. For compatibility with older versions of CMake, link " "library\n ", @@ -472,15 +484,15 @@ static bool HandleLibrary(cmMakefile& mf, cmTarget* target, // STATIC library.) if (currentProcessingState == ProcessingKeywordPrivateInterface || currentProcessingState == ProcessingPlainPrivateInterface) { - if (target->GetType() == cmStateEnums::STATIC_LIBRARY || - target->GetType() == cmStateEnums::OBJECT_LIBRARY) { + if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY || + this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { std::string configLib = - target->GetDebugGeneratorExpressions(libRef, llt); + this->Target->GetDebugGeneratorExpressions(lib, llt); if (cmGeneratorExpression::IsValidTargetName(lib) || cmGeneratorExpression::Find(lib) != std::string::npos) { configLib = "$<LINK_ONLY:" + configLib + ">"; } - target->AppendProperty("INTERFACE_LINK_LIBRARIES", configLib.c_str()); + this->AppendProperty("INTERFACE_LINK_LIBRARIES", configLib); } return true; } @@ -488,9 +500,8 @@ static bool HandleLibrary(cmMakefile& mf, cmTarget* target, // Handle general case where the command was called with another keyword than // PRIVATE / LINK_PRIVATE or none at all. (The "INTERFACE_LINK_LIBRARIES" // property of the target on the LHS shall be populated.) - target->AppendProperty( - "INTERFACE_LINK_LIBRARIES", - target->GetDebugGeneratorExpressions(libRef, llt).c_str()); + this->AppendProperty("INTERFACE_LINK_LIBRARIES", + this->Target->GetDebugGeneratorExpressions(lib, llt)); // Stop processing if called without any keyword. if (currentProcessingState == ProcessingLinkLibraries) { @@ -498,13 +509,13 @@ static bool HandleLibrary(cmMakefile& mf, cmTarget* target, } // Stop processing if policy CMP0022 is set to NEW. const cmPolicies::PolicyStatus policy22Status = - target->GetPolicyStatusCMP0022(); + this->Target->GetPolicyStatusCMP0022(); if (policy22Status != cmPolicies::OLD && policy22Status != cmPolicies::WARN) { return true; } // Stop processing if called with an INTERFACE library on the LHS. - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { return true; } @@ -514,7 +525,7 @@ static bool HandleLibrary(cmMakefile& mf, cmTarget* target, { // Get the list of configurations considered to be DEBUG. std::vector<std::string> debugConfigs = - mf.GetCMakeInstance()->GetDebugConfigs(); + this->Makefile.GetCMakeInstance()->GetDebugConfigs(); std::string prop; // Include this library in the link interface for the target. @@ -522,22 +533,49 @@ static bool HandleLibrary(cmMakefile& mf, cmTarget* target, // Put in the DEBUG configuration interfaces. for (std::string const& dc : debugConfigs) { prop = cmStrCat("LINK_INTERFACE_LIBRARIES_", dc); - target->AppendProperty(prop, libRef.c_str()); + this->AppendProperty(prop, lib); } } if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) { // Put in the non-DEBUG configuration interfaces. - target->AppendProperty("LINK_INTERFACE_LIBRARIES", libRef.c_str()); + this->AppendProperty("LINK_INTERFACE_LIBRARIES", lib); // Make sure the DEBUG configuration interfaces exist so that the // general one will not be used as a fall-back. for (std::string const& dc : debugConfigs) { prop = cmStrCat("LINK_INTERFACE_LIBRARIES_", dc); - if (!target->GetProperty(prop)) { - target->SetProperty(prop, ""); + if (!this->Target->GetProperty(prop)) { + this->Target->SetProperty(prop, ""); } } } } return true; } + +void TLL::AppendProperty(std::string const& prop, std::string const& value) +{ + this->AffectsProperty(prop); + this->Target->AppendProperty(prop, value); +} + +void TLL::AffectsProperty(std::string const& prop) +{ + if (!this->EncodeRemoteReference) { + return; + } + // Add a wrapper to the expression to tell LookupLinkItems to look up + // names in the caller's directory. + if (this->Props.insert(prop).second) { + this->Target->AppendProperty(prop, this->DirectoryId); + } +} + +TLL::~TLL() +{ + for (std::string const& prop : this->Props) { + this->Target->AppendProperty(prop, CMAKE_DIRECTORY_ID_SEP); + } +} + +} // namespace diff --git a/Source/cmTargetPrecompileHeadersCommand.cxx b/Source/cmTargetPrecompileHeadersCommand.cxx index c6e2e5c..0670bd9 100644 --- a/Source/cmTargetPrecompileHeadersCommand.cxx +++ b/Source/cmTargetPrecompileHeadersCommand.cxx @@ -47,9 +47,8 @@ private: bool /*prepend*/, bool /*system*/) override { std::string const& base = this->Makefile->GetCurrentSourceDirectory(); - tgt->AppendProperty( - "PRECOMPILE_HEADERS", - this->Join(ConvertToAbsoluteContent(content, base)).c_str()); + tgt->AppendProperty("PRECOMPILE_HEADERS", + this->Join(ConvertToAbsoluteContent(content, base))); return true; } diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index bbc1e16..0de8d6d 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -84,9 +84,7 @@ bool cmTargetPropCommandBase::HandleArguments( } ++argIndex; - this->Target->SetProperty("PRECOMPILE_HEADERS_REUSE_FROM", - args[argIndex].c_str()); - + this->Target->SetProperty("PRECOMPILE_HEADERS_REUSE_FROM", args[argIndex]); ++argIndex; } @@ -162,9 +160,8 @@ void cmTargetPropCommandBase::HandleInterfaceContent( const char* propValue = tgt->GetProperty(propName); const std::string totalContent = this->Join(content) + (propValue ? std::string(";") + propValue : std::string()); - tgt->SetProperty(propName, totalContent.c_str()); + tgt->SetProperty(propName, totalContent); } else { - tgt->AppendProperty("INTERFACE_" + this->Property, - this->Join(content).c_str()); + tgt->AppendProperty("INTERFACE_" + this->Property, this->Join(content)); } } diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx index baab8da..f37995c 100644 --- a/Source/cmTargetPropertyComputer.cxx +++ b/Source/cmTargetPropertyComputer.cxx @@ -62,6 +62,7 @@ bool cmTargetPropertyComputer::WhiteListedInterfaceProperty( "COMPATIBLE_INTERFACE_NUMBER_MAX", "COMPATIBLE_INTERFACE_NUMBER_MIN", "COMPATIBLE_INTERFACE_STRING", + "DEPRECATION", "EXPORT_NAME", "EXPORT_PROPERTIES", "IMPORTED", diff --git a/Source/cmTargetPropertyComputer.h b/Source/cmTargetPropertyComputer.h index 3b11acd..df34f18 100644 --- a/Source/cmTargetPropertyComputer.h +++ b/Source/cmTargetPropertyComputer.h @@ -46,10 +46,10 @@ private: cmListFileBacktrace const& context); template <typename Target> - static const char* ComputeLocationForBuild(Target const* tgt); + static const std::string& ComputeLocationForBuild(Target const* tgt); template <typename Target> - static const char* ComputeLocation(Target const* tgt, - std::string const& config); + static const std::string& ComputeLocation(Target const* tgt, + std::string const& config); template <typename Target> static const char* GetLocation(Target const* tgt, std::string const& prop, @@ -71,7 +71,7 @@ private: context)) { return nullptr; } - return ComputeLocationForBuild(tgt); + return ComputeLocationForBuild(tgt).c_str(); } // Support "LOCATION_<CONFIG>". @@ -82,7 +82,7 @@ private: return nullptr; } std::string configName = prop.substr(9); - return ComputeLocation(tgt, configName); + return ComputeLocation(tgt, configName).c_str(); } // Support "<CONFIG>_LOCATION". @@ -95,7 +95,7 @@ private: context)) { return nullptr; } - return ComputeLocation(tgt, configName); + return ComputeLocation(tgt, configName).c_str(); } } } diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx index c2e0b28..a1fbc9b 100644 --- a/Source/cmTargetSourcesCommand.cxx +++ b/Source/cmTargetSourcesCommand.cxx @@ -43,8 +43,7 @@ private: bool /*prepend*/, bool /*system*/) override { tgt->AppendProperty( - "SOURCES", - this->Join(ConvertToAbsoluteContent(tgt, content, false)).c_str()); + "SOURCES", this->Join(ConvertToAbsoluteContent(tgt, content, false))); return true; // Successfully handled. } diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx index d5c61c1..3b731cc 100644 --- a/Source/cmTest.cxx +++ b/Source/cmTest.cxx @@ -55,7 +55,7 @@ void cmTest::SetProperty(const std::string& prop, const char* value) this->Properties.SetProperty(prop, value); } -void cmTest::AppendProperty(const std::string& prop, const char* value, +void cmTest::AppendProperty(const std::string& prop, const std::string& value, bool asString) { this->Properties.AppendProperty(prop, value, asString); diff --git a/Source/cmTest.h b/Source/cmTest.h index dd246c4..72d4ed9 100644 --- a/Source/cmTest.h +++ b/Source/cmTest.h @@ -35,7 +35,7 @@ public: //! Set/Get a property of this source file void SetProperty(const std::string& prop, const char* value); - void AppendProperty(const std::string& prop, const char* value, + void AppendProperty(const std::string& prop, const std::string& value, bool asString = false); const char* GetProperty(const std::string& prop) const; bool GetPropertyAsBool(const std::string& prop) const; diff --git a/Source/cmUtilitySourceCommand.cxx b/Source/cmUtilitySourceCommand.cxx index a43165c..5865a19 100644 --- a/Source/cmUtilitySourceCommand.cxx +++ b/Source/cmUtilitySourceCommand.cxx @@ -102,15 +102,15 @@ bool cmUtilitySourceCommand(std::vector<std::string> const& args, cmSystemTools::ReplaceString(utilityExecutable, "/./", "/"); // Enter the value into the cache. - status.GetMakefile().AddCacheDefinition( - cacheEntry, utilityExecutable.c_str(), "Path to an internal program.", - cmStateEnums::FILEPATH); + status.GetMakefile().AddCacheDefinition(cacheEntry, utilityExecutable, + "Path to an internal program.", + cmStateEnums::FILEPATH); // add a value into the cache that maps from the // full path to the name of the project cmSystemTools::ConvertToUnixSlashes(utilityExecutable); - status.GetMakefile().AddCacheDefinition( - utilityExecutable, utilityName.c_str(), "Executable to project name.", - cmStateEnums::INTERNAL); + status.GetMakefile().AddCacheDefinition(utilityExecutable, utilityName, + "Executable to project name.", + cmStateEnums::INTERNAL); return true; } diff --git a/Source/cmVariableWatch.cxx b/Source/cmVariableWatch.cxx index 4995da9..35e1c8c 100644 --- a/Source/cmVariableWatch.cxx +++ b/Source/cmVariableWatch.cxx @@ -2,19 +2,19 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmVariableWatch.h" +#include <array> #include <memory> #include <utility> #include <vector> -static const char* const cmVariableWatchAccessStrings[] = { - "READ_ACCESS", "UNKNOWN_READ_ACCESS", "UNKNOWN_DEFINED_ACCESS", - "MODIFIED_ACCESS", "REMOVED_ACCESS", "NO_ACCESS" -}; - -const char* cmVariableWatch::GetAccessAsString(int access_type) +const std::string& cmVariableWatch::GetAccessAsString(int access_type) { + static const std::array<std::string, 6> cmVariableWatchAccessStrings = { + { "READ_ACCESS", "UNKNOWN_READ_ACCESS", "UNKNOWN_DEFINED_ACCESS", + "MODIFIED_ACCESS", "REMOVED_ACCESS", "NO_ACCESS" } + }; if (access_type < 0 || access_type >= cmVariableWatch::NO_ACCESS) { - return "NO_ACCESS"; + access_type = cmVariableWatch::NO_ACCESS; } return cmVariableWatchAccessStrings[access_type]; } diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h index e4b3b7c..6c418ed 100644 --- a/Source/cmVariableWatch.h +++ b/Source/cmVariableWatch.h @@ -46,7 +46,7 @@ public: */ enum { - VARIABLE_READ_ACCESS = 0, + VARIABLE_READ_ACCESS, UNKNOWN_VARIABLE_READ_ACCESS, UNKNOWN_VARIABLE_DEFINED_ACCESS, VARIABLE_MODIFIED_ACCESS, @@ -57,7 +57,7 @@ public: /** * Return the access as string */ - static const char* GetAccessAsString(int access_type); + static const std::string& GetAccessAsString(int access_type); protected: struct Pair diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx index f2c8f3c..35b9a1d 100644 --- a/Source/cmVariableWatchCommand.cxx +++ b/Source/cmVariableWatchCommand.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmVariableWatchCommand.h" +#include <limits> #include <memory> #include <utility> @@ -14,17 +15,19 @@ #include "cmVariableWatch.h" #include "cmake.h" +class cmLocalGenerator; + +namespace { struct cmVariableWatchCallbackData { bool InCallback; std::string Command; }; -static void cmVariableWatchCommandVariableAccessed(const std::string& variable, - int access_type, - void* client_data, - const char* newValue, - const cmMakefile* mf) +void cmVariableWatchCommandVariableAccessed(const std::string& variable, + int access_type, void* client_data, + const char* newValue, + const cmMakefile* mf) { cmVariableWatchCallbackData* data = static_cast<cmVariableWatchCallbackData*>(client_data); @@ -34,40 +37,35 @@ static void cmVariableWatchCommandVariableAccessed(const std::string& variable, } data->InCallback = true; - cmListFileFunction newLFF; - cmListFileArgument arg; - bool processed = false; - const char* accessString = cmVariableWatch::GetAccessAsString(access_type); - const char* currentListFile = mf->GetDefinition("CMAKE_CURRENT_LIST_FILE"); + auto accessString = cmVariableWatch::GetAccessAsString(access_type); /// Ultra bad!! cmMakefile* makefile = const_cast<cmMakefile*>(mf); std::string stack = makefile->GetProperty("LISTFILE_STACK"); if (!data->Command.empty()) { - newLFF.Arguments.clear(); - newLFF.Arguments.emplace_back(variable, cmListFileArgument::Quoted, 9999); - newLFF.Arguments.emplace_back(accessString, cmListFileArgument::Quoted, - 9999); - newLFF.Arguments.emplace_back(newValue ? newValue : "", - cmListFileArgument::Quoted, 9999); - newLFF.Arguments.emplace_back(currentListFile, cmListFileArgument::Quoted, - 9999); - newLFF.Arguments.emplace_back(stack, cmListFileArgument::Quoted, 9999); + cmListFileFunction newLFF; + const char* const currentListFile = + mf->GetDefinition("CMAKE_CURRENT_LIST_FILE"); + const auto fakeLineNo = + std::numeric_limits<decltype(cmListFileArgument::Line)>::max(); + newLFF.Arguments = { + { variable, cmListFileArgument::Quoted, fakeLineNo }, + { accessString, cmListFileArgument::Quoted, fakeLineNo }, + { newValue ? newValue : "", cmListFileArgument::Quoted, fakeLineNo }, + { currentListFile, cmListFileArgument::Quoted, fakeLineNo }, + { stack, cmListFileArgument::Quoted, fakeLineNo } + }; newLFF.Name = data->Command; - newLFF.Line = 9999; + newLFF.Line = fakeLineNo; cmExecutionStatus status(*makefile); if (!makefile->ExecuteCommand(newLFF, status)) { cmSystemTools::Error( cmStrCat("Error in cmake code at\nUnknown:0:\nA command failed " "during the invocation of callback \"", data->Command, "\".")); - data->InCallback = false; - return; } - processed = true; - } - if (!processed) { + } else { makefile->IssueMessage( MessageType::LOG, cmStrCat("Variable \"", variable, "\" was accessed using ", accessString, @@ -77,7 +75,7 @@ static void cmVariableWatchCommandVariableAccessed(const std::string& variable, data->InCallback = false; } -static void deleteVariableWatchCallbackData(void* client_data) +void deleteVariableWatchCallbackData(void* client_data) { cmVariableWatchCallbackData* data = static_cast<cmVariableWatchCallbackData*>(client_data); @@ -91,18 +89,18 @@ class FinalAction public: /* NOLINTNEXTLINE(performance-unnecessary-value-param) */ FinalAction(cmMakefile* makefile, std::string variable) - : Action(std::make_shared<Impl>(makefile, std::move(variable))) + : Action{ std::make_shared<Impl>(makefile, std::move(variable)) } { } - void operator()(cmMakefile&) const {} + void operator()(cmLocalGenerator&, const cmListFileBacktrace&) const {} private: struct Impl { Impl(cmMakefile* makefile, std::string variable) - : Makefile(makefile) - , Variable(std::move(variable)) + : Makefile{ makefile } + , Variable{ std::move(variable) } { } @@ -112,12 +110,13 @@ private: this->Variable, cmVariableWatchCommandVariableAccessed); } - cmMakefile* Makefile; - std::string Variable; + cmMakefile* const Makefile; + std::string const Variable; }; std::shared_ptr<Impl const> Action; }; +} // anonymous namespace bool cmVariableWatchCommand(std::vector<std::string> const& args, cmExecutionStatus& status) @@ -136,10 +135,10 @@ bool cmVariableWatchCommand(std::vector<std::string> const& args, return false; } - cmVariableWatchCallbackData* data = new cmVariableWatchCallbackData; + auto* const data = new cmVariableWatchCallbackData; data->InCallback = false; - data->Command = command; + data->Command = std::move(command); if (!status.GetMakefile().GetCMakeInstance()->GetVariableWatch()->AddWatch( variable, cmVariableWatchCommandVariableAccessed, data, @@ -148,7 +147,7 @@ bool cmVariableWatchCommand(std::vector<std::string> const& args, return false; } - status.GetMakefile().AddFinalAction( - FinalAction(&status.GetMakefile(), variable)); + status.GetMakefile().AddGeneratorAction( + FinalAction{ &status.GetMakefile(), variable }); return true; } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index f220ea5..121ff6e 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -6,6 +6,7 @@ #include <set> #include <cm/memory> +#include <cm/vector> #include "windows.h" @@ -52,7 +53,7 @@ struct cmVisualStudio10TargetGenerator::Elem bool HasContent = false; std::string Tag; - Elem(std::ostream& s, const char* tag) + Elem(std::ostream& s, const std::string& tag) : S(s) , Indent(0) , Tag(tag) @@ -60,7 +61,7 @@ struct cmVisualStudio10TargetGenerator::Elem this->StartElement(); } Elem(const Elem&) = delete; - Elem(Elem& par, const char* tag) + Elem(Elem& par, const std::string& tag) : S(par.S) , Indent(par.Indent + 1) , Tag(tag) @@ -71,13 +72,13 @@ struct cmVisualStudio10TargetGenerator::Elem void SetHasElements() { if (!HasElements) { - this->S << ">\n"; + this->S << ">"; HasElements = true; } } std::ostream& WriteString(const char* line); void StartElement() { this->WriteString("<") << this->Tag; } - void Element(const char* tag, const std::string& val) + void Element(const std::string& tag, const std::string& val) { Elem(*this, tag).Content(val); } @@ -103,19 +104,14 @@ struct cmVisualStudio10TargetGenerator::Elem if (HasElements) { this->WriteString("</") << this->Tag << ">"; - if (this->Indent > 0) { - this->S << '\n'; - } else { - // special case: don't print EOL at EOF - } } else if (HasContent) { - this->S << "</" << this->Tag << ">\n"; + this->S << "</" << this->Tag << ">"; } else { - this->S << " />\n"; + this->S << " />"; } } - void WritePlatformConfigTag(const char* tag, const std::string& cond, + void WritePlatformConfigTag(const std::string& tag, const std::string& cond, const std::string& content); }; @@ -131,8 +127,8 @@ public: { } - void OutputFlag(std::ostream& /*fout*/, int /*indent*/, const char* tag, - const std::string& content) override + void OutputFlag(std::ostream& /*fout*/, int /*indent*/, + const std::string& tag, const std::string& content) override { if (!this->GetConfiguration().empty()) { // if there are configuration specific flags, then @@ -274,7 +270,7 @@ std::string cmVisualStudio10TargetGenerator::CalcCondition( } void cmVisualStudio10TargetGenerator::Elem::WritePlatformConfigTag( - const char* tag, const std::string& cond, const std::string& content) + const std::string& tag, const std::string& cond, const std::string& content) { Elem(*this, tag).Attribute("Condition", cond).Content(content); } @@ -282,6 +278,7 @@ void cmVisualStudio10TargetGenerator::Elem::WritePlatformConfigTag( std::ostream& cmVisualStudio10TargetGenerator::Elem::WriteString( const char* line) { + this->S << '\n'; this->S.fill(' '); this->S.width(this->Indent * 2); // write an empty string to get the fill level indent to print @@ -334,9 +331,9 @@ void cmVisualStudio10TargetGenerator::Generate() } // Tell the global generator the name of the project file this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME", - this->Name.c_str()); + this->Name); this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME_EXT", - ProjectFileExtension.c_str()); + ProjectFileExtension); this->DotNetHintReferences.clear(); this->AdditionalUsingDirectories.clear(); if (this->GeneratorTarget->GetType() <= cmStateEnums::OBJECT_LIBRARY) { @@ -376,8 +373,7 @@ void cmVisualStudio10TargetGenerator::Generate() char magic[] = { char(0xEF), char(0xBB), char(0xBF) }; BuildFileStream.write(magic, 3); BuildFileStream << "<?xml version=\"1.0\" encoding=\"" - << this->GlobalGenerator->Encoding() << "\"?>" - << "\n"; + << this->GlobalGenerator->Encoding() << "\"?>"; { Elem e0(BuildFileStream, "Project"); e0.Attribute("DefaultTargets", "Build"); @@ -488,23 +484,33 @@ void cmVisualStudio10TargetGenerator::Generate() } e1.Element("ProjectName", projLabel); { - // TODO: add deprecation warning for VS_* property? - const char* targetFrameworkVersion = - this->GeneratorTarget->GetProperty( - "VS_DOTNET_TARGET_FRAMEWORK_VERSION"); - if (!targetFrameworkVersion) { - targetFrameworkVersion = this->GeneratorTarget->GetProperty( - "DOTNET_TARGET_FRAMEWORK_VERSION"); - } - if (!targetFrameworkVersion && this->ProjectType == csproj && - this->GlobalGenerator->TargetsWindowsCE() && - this->GlobalGenerator->GetVersion() == - cmGlobalVisualStudioGenerator::VS12) { - // VS12 .NETCF default to .NET framework 3.9 - targetFrameworkVersion = "v3.9"; - } - if (targetFrameworkVersion) { - e1.Element("TargetFrameworkVersion", targetFrameworkVersion); + const char* targetFramework = + this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK"); + if (targetFramework) { + if (std::strchr(targetFramework, ';') != nullptr) { + e1.Element("TargetFrameworks", targetFramework); + } else { + e1.Element("TargetFramework", targetFramework); + } + } else { + // TODO: add deprecation warning for VS_* property? + const char* targetFrameworkVersion = + this->GeneratorTarget->GetProperty( + "VS_DOTNET_TARGET_FRAMEWORK_VERSION"); + if (!targetFrameworkVersion) { + targetFrameworkVersion = this->GeneratorTarget->GetProperty( + "DOTNET_TARGET_FRAMEWORK_VERSION"); + } + if (!targetFrameworkVersion && this->ProjectType == csproj && + this->GlobalGenerator->TargetsWindowsCE() && + this->GlobalGenerator->GetVersion() == + cmGlobalVisualStudioGenerator::VS12) { + // VS12 .NETCF default to .NET framework 3.9 + targetFrameworkVersion = "v3.9"; + } + if (targetFrameworkVersion) { + e1.Element("TargetFrameworkVersion", targetFrameworkVersion); + } } if (this->ProjectType == vcxproj && this->GlobalGenerator->TargetsWindowsCE()) { @@ -543,6 +549,11 @@ void cmVisualStudio10TargetGenerator::Generate() e1.Element("VCProjectUpgraderObjectName", "NoUpgrade"); } + if (const char* vcTargetsPath = + this->GlobalGenerator->GetCustomVCTargetsPath()) { + e1.Element("VCTargetsPath", vcTargetsPath); + } + std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys(); for (std::string const& keyIt : keys) { static const char* prefix = "VS_GLOBAL_"; @@ -557,7 +568,7 @@ void cmVisualStudio10TargetGenerator::Generate() const char* value = this->GeneratorTarget->GetProperty(keyIt); if (!value) continue; - e1.Element(globalKey.c_str(), value); + e1.Element(globalKey, value); } if (this->Managed) { @@ -676,6 +687,8 @@ void cmVisualStudio10TargetGenerator::Generate() this->WritePlatformExtensions(e1); } + + this->WriteDotNetDocumentationFile(e0); Elem(e0, "PropertyGroup").Attribute("Label", "UserMacros"); this->WriteWinRTPackageCertificateKeyFile(e0); this->WritePathAndIncrementalLinkOptions(e0); @@ -906,7 +919,19 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferenceCustomTags( } } for (auto const& tag : tags) { - e2.Element(tag.first.c_str(), tag.second); + e2.Element(tag.first, tag.second); + } +} + +void cmVisualStudio10TargetGenerator::WriteDotNetDocumentationFile(Elem& e0) +{ + std::string const documentationFile = + this->GeneratorTarget->GetSafeProperty("VS_DOTNET_DOCUMENTATION_FILE"); + + if (this->ProjectType == csproj && !documentationFile.empty()) { + Elem e1(e0, "PropertyGroup"); + Elem e2(e1, "DocumentationFile"); + e2.Content(documentationFile); } } @@ -956,17 +981,11 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) // If the resource was NOT added using a relative path (which should // be the default), we have to provide a link here if (!useRelativePath) { - std::string link; - if (obj.find(srcDir) == 0) { - link = obj.substr(srcDir.length() + 1); - } else if (obj.find(binDir) == 0) { - link = obj.substr(binDir.length() + 1); - } else { + std::string link = this->GetCSharpSourceLink(oi); + if (link.empty()) { link = cmsys::SystemTools::GetFilenameName(obj); } - if (!link.empty()) { - e2.Element("Link", link); - } + e2.Element("Link", link); } // Determine if this is a generated resource from a .Designer.cs file std::string designerResource = @@ -1000,7 +1019,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) if (!tagName.empty()) { std::string value = props.GetPropertyValue(p); if (!value.empty()) { - e2.Element(tagName.c_str(), value); + e2.Element(tagName, value); } } } @@ -1029,25 +1048,6 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup(Elem& e0) Elem e2(e1, xamlType); this->WriteSource(e2, oi); e2.SetHasElements(); - if (this->ProjectType == csproj && !this->InSourceBuild) { - // add <Link> tag to written XAML source if necessary - const std::string& srcDir = - this->Makefile->GetCurrentSourceDirectory(); - const std::string& binDir = - this->Makefile->GetCurrentBinaryDirectory(); - std::string link; - if (obj.find(srcDir) == 0) { - link = obj.substr(srcDir.length() + 1); - } else if (obj.find(binDir) == 0) { - link = obj.substr(binDir.length() + 1); - } else { - link = cmsys::SystemTools::GetFilenameName(obj); - } - if (!link.empty()) { - ConvertToWindowsSlash(link); - e2.Element("Link", link); - } - } e2.Element("SubType", "Designer"); } } @@ -1417,13 +1417,8 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( } else { Elem e1(e0, "ItemGroup"); Elem e2(e1, "None"); - std::string link; - this->GetCSharpSourceLink(source, link); this->WriteSource(e2, source); e2.SetHasElements(); - if (!link.empty()) { - e2.Element("Link", link); - } } for (std::string const& c : this->Configurations) { cmCustomCommandGenerator ccg(command, c, lg); @@ -1598,8 +1593,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups() fout.write(magic, 3); fout << "<?xml version=\"1.0\" encoding=\"" - << this->GlobalGenerator->Encoding() << "\"?>" - << "\n"; + << this->GlobalGenerator->Encoding() << "\"?>"; { Elem e0(fout, "Project"); e0.Attribute("ToolsVersion", this->GlobalGenerator->GetToolsVersion()); @@ -1738,7 +1732,7 @@ void cmVisualStudio10TargetGenerator::WriteGroupSources( std::string const& filter = sourceGroup->GetFullName(); std::string path = this->ConvertPath(source, s.RelativePath); ConvertToWindowsSlash(path); - Elem e2(e1, name.c_str()); + Elem e2(e1, name); e2.Attribute("Include", path); if (!filter.empty()) { e2.Element("Filter", filter); @@ -1781,30 +1775,8 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, std::string copyToOutDir; std::string includeInVsix; std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); - if (this->ProjectType == csproj) { - // EVERY extra source file must have a <Link>, otherwise it might not - // be visible in Visual Studio at all. The path relative to current - // source- or binary-dir is used within the link, if the file is - // in none of these paths, it is added with the plain filename without - // any path. This means the file will show up at root-level of the csproj - // (where CMakeLists.txt etc. are). - if (!this->InSourceBuild) { - toolHasSettings = true; - std::string fullFileName = sf->GetFullPath(); - std::string srcDir = this->Makefile->GetCurrentSourceDirectory(); - std::string binDir = this->Makefile->GetCurrentBinaryDirectory(); - if (fullFileName.find(binDir) != std::string::npos) { - sourceLink.clear(); - } else if (fullFileName.find(srcDir) != std::string::npos) { - sourceLink = fullFileName.substr(srcDir.length() + 1); - } else { - // fallback: add plain filename without any path - sourceLink = cmsys::SystemTools::GetFilenameName(fullFileName); - } - if (!sourceLink.empty()) { - ConvertToWindowsSlash(sourceLink); - } - } + if (this->ProjectType == csproj && !this->InSourceBuild) { + toolHasSettings = true; } if (ext == "hlsl") { tool = "FXCompile"; @@ -2023,9 +1995,6 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, if (!settingsLastGenOutput.empty()) { e2.Element("LastGenOutput", settingsLastGenOutput); } - if (!sourceLink.empty()) { - e2.Element("Link", sourceLink); - } if (!subType.empty()) { e2.Element("SubType", subType); } @@ -2078,6 +2047,20 @@ void cmVisualStudio10TargetGenerator::WriteSource(Elem& e2, ConvertToWindowsSlash(sourceFile); e2.Attribute("Include", sourceFile); + if (this->ProjectType == csproj && !this->InSourceBuild) { + // For out of source projects we have to provide a link (if not specified + // via property) for every source file (besides .cs files) otherwise they + // will not be visible in VS at all. + // First we check if the file is in a source group, then we check if the + // file path is relative to current source- or binary-dir, otherwise it is + // added with the plain filename without any path. This means the file will + // show up at root-level of the csproj (where CMakeLists.txt etc. are). + std::string link = this->GetCSharpSourceLink(sf); + if (link.empty()) + link = cmsys::SystemTools::GetFilenameName(sf->GetFullPath()); + e2.Element("Link", link); + } + ToolSource toolSource = { sf, forceRelative }; this->Tools[e2.Tag].push_back(toolSource); } @@ -2437,12 +2420,6 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( std::string f = source->GetFullPath(); using CsPropMap = std::map<std::string, std::string>; CsPropMap sourceFileTags; - // set <Link> tag if necessary - std::string link; - this->GetCSharpSourceLink(source, link); - if (!link.empty()) { - sourceFileTags["Link"] = link; - } this->GetCSharpSourceProperties(&sf, sourceFileTags); // write source file specific tags if (!sourceFileTags.empty()) { @@ -2624,9 +2601,9 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental( // Some link options belong here. Use them now and remove them so that // WriteLinkOptions does not use them. - const char* flags[] = { "LinkDelaySign", "LinkKeyFile", 0 }; - for (const char** f = flags; *f; ++f) { - const char* flag = *f; + static const std::vector<std::string> flags{ "LinkDelaySign", + "LinkKeyFile" }; + for (const std::string& flag : flags) { if (const char* value = linkOptions.GetFlag(flag)) { e1.WritePlatformConfigTag(flag, cond, value); linkOptions.RemoveFlag(flag); @@ -2790,6 +2767,9 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( case csproj: this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName, "CSharp"); + cm::erase_if(targetDefines, [](std::string const& def) { + return def.find('=') != std::string::npos; + }); break; } clOptions.AddDefines(targetDefines); @@ -2818,10 +2798,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( } if (this->MSTools) { - // If we have the VS_WINRT_COMPONENT or CMAKE_VS_WINRT_BY_DEFAULT - // set then force Compile as WinRT. - if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") || - this->Makefile->IsOn("CMAKE_VS_WINRT_BY_DEFAULT")) { + // If we have the VS_WINRT_COMPONENT set then force Compile as WinRT + if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT")) { clOptions.AddFlag("CompileAsWinRT", "true"); // For WinRT components, add the _WINRT_DLL define to produce a lib if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY || @@ -2829,7 +2807,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( clOptions.AddDefine("_WINRT_DLL"); } } else if (this->GlobalGenerator->TargetsWindowsStore() || - this->GlobalGenerator->TargetsWindowsPhone()) { + this->GlobalGenerator->TargetsWindowsPhone() || + this->Makefile->IsOn("CMAKE_VS_WINRT_BY_DEFAULT")) { if (!clOptions.IsWinRt()) { clOptions.AddFlag("CompileAsWinRT", "false"); } @@ -3626,18 +3605,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( this->AddLibraries(cli, libVec, vsTargetVec, config); if (cmContains(linkClosure->Languages, "CUDA") && this->CudaOptions[config] != nullptr) { - switch (this->CudaOptions[config]->GetCudaRuntime()) { - case cmVisualStudioGeneratorOptions::CudaRuntimeStatic: - libVec.push_back("cudadevrt.lib"); - libVec.push_back("cudart_static.lib"); - break; - case cmVisualStudioGeneratorOptions::CudaRuntimeShared: - libVec.push_back("cudadevrt.lib"); - libVec.push_back("cudart.lib"); - break; - case cmVisualStudioGeneratorOptions::CudaRuntimeNone: - break; - } + this->CudaOptions[config]->FixCudaRuntime(this->GeneratorTarget); } std::string standardLibsVar = cmStrCat("CMAKE_", linkLanguage, "_STANDARD_LIBRARIES"); @@ -4027,8 +3995,8 @@ void cmVisualStudio10TargetGenerator::WriteEvents( } void cmVisualStudio10TargetGenerator::WriteEvent( - Elem& e1, const char* name, std::vector<cmCustomCommand> const& commands, - std::string const& configName) + Elem& e1, const std::string& name, + std::vector<cmCustomCommand> const& commands, std::string const& configName) { if (commands.empty()) { return; @@ -4100,6 +4068,9 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0) e2.Element("Project", "{" + this->GlobalGenerator->GetGUID(name) + "}"); e2.Element("Name", name); this->WriteDotNetReferenceCustomTags(e2, name); + if (dt->IsCSharpOnly() || cmHasLiteralSuffix(path, "csproj")) { + e2.Element("SkipGetTargetFrameworkProperties", "true"); + } // Don't reference targets that don't produce any output. if (dt->GetManagedType("") == cmGeneratorTarget::ManagedType::Undefined) { @@ -4847,28 +4818,38 @@ void cmVisualStudio10TargetGenerator::WriteCSharpSourceProperties( Elem& e2, const std::map<std::string, std::string>& tags) { for (const auto& i : tags) { - e2.Element(i.first.c_str(), i.second); + e2.Element(i.first, i.second); } } -void cmVisualStudio10TargetGenerator::GetCSharpSourceLink( - cmSourceFile const* sf, std::string& link) +std::string cmVisualStudio10TargetGenerator::GetCSharpSourceLink( + cmSourceFile const* source) { - std::string const& sourceFilePath = sf->GetFullPath(); - std::string const& binaryDir = LocalGenerator->GetCurrentBinaryDirectory(); - - if (!cmSystemTools::IsSubDirectory(sourceFilePath, binaryDir)) { - const std::string& stripFromPath = - this->Makefile->GetCurrentSourceDirectory(); - if (sourceFilePath.find(stripFromPath) == 0) { - if (const char* l = sf->GetProperty("VS_CSHARP_Link")) { - link = l; - } else { - link = sourceFilePath.substr(stripFromPath.length() + 1); - } - ConvertToWindowsSlash(link); - } - } + // For out of source files, we first check if a matching source group + // for this file exists, otherwise we check if the path relative to current + // source- or binary-dir is used within the link and return that + std::string link; + std::string const& fullFileName = source->GetFullPath(); + std::string const& srcDir = this->Makefile->GetCurrentSourceDirectory(); + std::string const& binDir = this->Makefile->GetCurrentBinaryDirectory(); + // unfortunately we have to copy the source groups, because + // FindSourceGroup uses a regex which is modifying the group + std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups(); + cmSourceGroup* sourceGroup = + this->Makefile->FindSourceGroup(fullFileName, sourceGroups); + if (sourceGroup && !sourceGroup->GetFullName().empty()) { + link = sourceGroup->GetFullName() + "/" + + cmsys::SystemTools::GetFilenameName(fullFileName); + } else if (fullFileName.find(srcDir) == 0) { + link = fullFileName.substr(srcDir.length() + 1); + } else if (fullFileName.find(binDir) == 0) { + link = fullFileName.substr(binDir.length() + 1); + } else if (const char* l = source->GetProperty("VS_CSHARP_Link")) { + link = l; + } + + ConvertToWindowsSlash(link); + return link; } std::string cmVisualStudio10TargetGenerator::GetCMakeFilePath( diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index a18a33d..4977c1a 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -79,6 +79,7 @@ private: void WriteDotNetReference(Elem& e1, std::string const& ref, std::string const& hint, std::string const& config); + void WriteDotNetDocumentationFile(Elem& e0); void WriteImports(Elem& e0); void WriteDotNetReferenceCustomTags(Elem& e2, std::string const& ref); void WriteEmbeddedResourceGroup(Elem& e0); @@ -164,7 +165,7 @@ private: void WriteLibOptions(Elem& e1, std::string const& config); void WriteManifestOptions(Elem& e1, std::string const& config); void WriteEvents(Elem& e1, std::string const& configName); - void WriteEvent(Elem& e1, const char* name, + void WriteEvent(Elem& e1, std::string const& name, std::vector<cmCustomCommand> const& commands, std::string const& configName); void WriteGroupSources(Elem& e0, std::string const& name, @@ -182,7 +183,7 @@ private: std::map<std::string, std::string>& tags); void WriteCSharpSourceProperties( Elem& e2, const std::map<std::string, std::string>& tags); - void GetCSharpSourceLink(cmSourceFile const* sf, std::string& link); + std::string GetCSharpSourceLink(cmSourceFile const* source); private: friend class cmVS10GeneratorOptions; diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index 1139aa9..4004b66 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -3,6 +3,8 @@ #include <cm/iterator> #include "cmAlgorithms.h" +#include "cmGeneratorExpression.h" +#include "cmGeneratorTarget.h" #include "cmLocalVisualStudioGenerator.h" #include "cmOutputConverter.h" #include "cmSystemTools.h" @@ -149,25 +151,33 @@ bool cmVisualStudioGeneratorOptions::UsingSBCS() const return false; } -cmVisualStudioGeneratorOptions::CudaRuntime -cmVisualStudioGeneratorOptions::GetCudaRuntime() const +void cmVisualStudioGeneratorOptions::FixCudaRuntime(cmGeneratorTarget* target) { std::map<std::string, FlagValue>::const_iterator i = this->FlagMap.find("CudaRuntime"); - if (i != this->FlagMap.end() && i->second.size() == 1) { - std::string const& cudaRuntime = i->second[0]; - if (cudaRuntime == "Static") { - return CudaRuntimeStatic; - } - if (cudaRuntime == "Shared") { - return CudaRuntimeShared; - } - if (cudaRuntime == "None") { - return CudaRuntimeNone; + if (i == this->FlagMap.end()) { + // User didn't provide am override so get the property value + const char* runtimeLibraryValue = + target->GetProperty("CUDA_RUNTIME_LIBRARY"); + if (runtimeLibraryValue) { + std::string cudaRuntime = + cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate( + runtimeLibraryValue, this->LocalGenerator, this->Configuration, + target)); + if (cudaRuntime == "STATIC") { + this->AddFlag("CudaRuntime", "Static"); + } + if (cudaRuntime == "SHARED") { + this->AddFlag("CudaRuntime", "Shared"); + } + if (cudaRuntime == "NONE") { + this->AddFlag("CudaRuntime", "None"); + } + } else { + // nvcc default is static + this->AddFlag("CudaRuntime", "Static"); } } - // nvcc default is static - return CudaRuntimeStatic; } void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() @@ -431,7 +441,7 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions( if (this->Defines.empty()) { return; } - const char* tag = "PreprocessorDefinitions"; + std::string tag = "PreprocessorDefinitions"; if (lang == "CUDA") { tag = "Defines"; } @@ -473,7 +483,7 @@ void cmVisualStudioGeneratorOptions::OutputAdditionalIncludeDirectories( return; } - const char* tag = "AdditionalIncludeDirectories"; + std::string tag = "AdditionalIncludeDirectories"; if (lang == "CUDA") { tag = "Include"; } else if (lang == "ASM_MASM" || lang == "ASM_NASM") { @@ -528,6 +538,6 @@ void cmVisualStudioGeneratorOptions::OutputFlagMap(std::ostream& fout, sep = ";"; } - this->OutputFlag(fout, indent, m.first.c_str(), oss.str()); + this->OutputFlag(fout, indent, m.first, oss.str()); } } diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index 560593e..b335694 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -13,6 +13,7 @@ #include "cmIDEOptions.h" class cmLocalVisualStudioGenerator; +class cmGeneratorTarget; using cmVS7FlagTable = cmIDEFlagTable; @@ -61,15 +62,8 @@ public: bool UsingUnicode() const; bool UsingSBCS() const; - enum CudaRuntime - { - CudaRuntimeStatic, - CudaRuntimeShared, - CudaRuntimeNone - }; - CudaRuntime GetCudaRuntime() const; - void FixCudaCodeGeneration(); + void FixCudaRuntime(cmGeneratorTarget* target); void FixManifestUACFlags(); @@ -86,7 +80,8 @@ public: const std::string& GetConfiguration() const; protected: - virtual void OutputFlag(std::ostream& fout, int indent, const char* tag, + virtual void OutputFlag(std::ostream& fout, int indent, + const std::string& tag, const std::string& content) = 0; private: diff --git a/Source/cmXCode21Object.cxx b/Source/cmXCode21Object.cxx index a9bb2ef..6b133a9 100644 --- a/Source/cmXCode21Object.cxx +++ b/Source/cmXCode21Object.cxx @@ -30,11 +30,12 @@ void cmXCode21Object::PrintComment(std::ostream& out) out << " */"; } -void cmXCode21Object::PrintList(std::vector<cmXCodeObject*> const& v, - std::ostream& out, PBXType t) +void cmXCode21Object::PrintList( + std::vector<std::unique_ptr<cmXCodeObject>> const& v, std::ostream& out, + PBXType t) { bool hasOne = false; - for (auto obj : v) { + for (const auto& obj : v) { if (obj->GetType() == OBJECT && obj->GetIsA() == t) { hasOne = true; break; @@ -44,7 +45,7 @@ void cmXCode21Object::PrintList(std::vector<cmXCodeObject*> const& v, return; } out << "\n/* Begin " << PBXTypeNames[t] << " section */\n"; - for (auto obj : v) { + for (const auto& obj : v) { if (obj->GetType() == OBJECT && obj->GetIsA() == t) { obj->Print(out); } @@ -52,8 +53,8 @@ void cmXCode21Object::PrintList(std::vector<cmXCodeObject*> const& v, out << "/* End " << PBXTypeNames[t] << " section */\n"; } -void cmXCode21Object::PrintList(std::vector<cmXCodeObject*> const& v, - std::ostream& out) +void cmXCode21Object::PrintList( + std::vector<std::unique_ptr<cmXCodeObject>> const& v, std::ostream& out) { cmXCodeObject::Indent(1, out); out << "objects = {\n"; diff --git a/Source/cmXCode21Object.h b/Source/cmXCode21Object.h index 8e4b80f..76fad23 100644 --- a/Source/cmXCode21Object.h +++ b/Source/cmXCode21Object.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <memory> #include <vector> #include "cmXCodeObject.h" @@ -15,8 +16,9 @@ class cmXCode21Object : public cmXCodeObject public: cmXCode21Object(PBXType ptype, Type type); void PrintComment(std::ostream&) override; - static void PrintList(std::vector<cmXCodeObject*> const&, std::ostream& out, - PBXType t); - static void PrintList(std::vector<cmXCodeObject*> const&, std::ostream& out); + static void PrintList(std::vector<std::unique_ptr<cmXCodeObject>> const&, + std::ostream& out, PBXType t); + static void PrintList(std::vector<std::unique_ptr<cmXCodeObject>> const&, + std::ostream& out); }; #endif diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx index afc95f5..b34c2f6 100644 --- a/Source/cmXCodeScheme.cxx +++ b/Source/cmXCodeScheme.cxx @@ -8,13 +8,16 @@ #include <utility> #include "cmGeneratedFileStream.h" +#include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmXMLSafe.h" -cmXCodeScheme::cmXCodeScheme(cmXCodeObject* xcObj, TestObjects tests, +cmXCodeScheme::cmXCodeScheme(cmLocalGenerator* lg, cmXCodeObject* xcObj, + TestObjects tests, const std::vector<std::string>& configList, unsigned int xcVersion) - : Target(xcObj) + : LocalGenerator(lg) + , Target(xcObj) , Tests(std::move(tests)) , TargetName(xcObj->GetTarget()->GetName()) , ConfigList(configList) @@ -135,7 +138,8 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout, xout.Attribute("selectedLauncherIdentifier", "Xcode.DebuggerFoundation.Launcher.LLDB"); xout.Attribute("launchStyle", "0"); - xout.Attribute("useCustomWorkingDirectory", "NO"); + WriteCustomWorkingDirectory(xout, configuration); + xout.Attribute("ignoresPersistentStateOnLaunch", "NO"); WriteLaunchActionBooleanAttribute(xout, "debugDocumentVersioning", "XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING", @@ -355,7 +359,7 @@ void cmXCodeScheme::WriteProfileAction(cmXMLWriter& xout, xout.Attribute("buildConfiguration", configuration); xout.Attribute("shouldUseLaunchSchemeArgsEnv", "YES"); xout.Attribute("savedToolIdentifier", ""); - xout.Attribute("useCustomWorkingDirectory", "NO"); + WriteCustomWorkingDirectory(xout, configuration); WriteLaunchActionBooleanAttribute(xout, "debugDocumentVersioning", "XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING", true); @@ -395,6 +399,22 @@ void cmXCodeScheme::WriteBuildableReference(cmXMLWriter& xout, xout.EndElement(); } +void cmXCodeScheme::WriteCustomWorkingDirectory( + cmXMLWriter& xout, const std::string& configuration) +{ + std::string propertyValue = this->Target->GetTarget()->GetSafeProperty( + "XCODE_SCHEME_WORKING_DIRECTORY"); + if (propertyValue.empty()) { + xout.Attribute("useCustomWorkingDirectory", "NO"); + } else { + xout.Attribute("useCustomWorkingDirectory", "YES"); + + auto customWorkingDirectory = cmGeneratorExpression::Evaluate( + propertyValue, this->LocalGenerator, configuration); + xout.Attribute("customWorkingDirectory", customWorkingDirectory); + } +} + std::string cmXCodeScheme::WriteVersionString() { std::ostringstream v; diff --git a/Source/cmXCodeScheme.h b/Source/cmXCodeScheme.h index dff5e35..da40856 100644 --- a/Source/cmXCodeScheme.h +++ b/Source/cmXCodeScheme.h @@ -20,7 +20,7 @@ class cmXCodeScheme public: using TestObjects = std::vector<const cmXCodeObject*>; - cmXCodeScheme(cmXCodeObject* xcObj, TestObjects tests, + cmXCodeScheme(cmLocalGenerator* lg, cmXCodeObject* xcObj, TestObjects tests, const std::vector<std::string>& configList, unsigned int xcVersion); @@ -28,6 +28,7 @@ public: const std::string& container); private: + cmLocalGenerator* const LocalGenerator; const cmXCodeObject* const Target; const TestObjects Tests; const std::string& TargetName; @@ -63,6 +64,9 @@ private: void WriteBuildableReference(cmXMLWriter& xout, const cmXCodeObject* xcObj, const std::string& container); + void WriteCustomWorkingDirectory(cmXMLWriter& xout, + const std::string& configuration); + std::string WriteVersionString(); std::string FindConfiguration(const std::string& name); diff --git a/Source/cm_get_date.c b/Source/cm_get_date.c index 4bef803..49f5577 100644 --- a/Source/cm_get_date.c +++ b/Source/cm_get_date.c @@ -2,6 +2,10 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cm_get_date.h" +// FIXME: This suppresses use of localtime_r because archive_getdate.c +// depends the rest of libarchive's checks for that. +#define CM_GET_DATE + #define __archive_get_date cm_get_date #include "../Utilities/cmlibarchive/libarchive/archive_getdate.c" diff --git a/Source/cmake.cxx b/Source/cmake.cxx index f63a264..f4b9f16 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -2,12 +2,27 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmake.h" +#include <algorithm> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <initializer_list> +#include <iostream> +#include <sstream> +#include <utility> + #include <cm/memory> #include <cm/string_view> #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW) # include <cm/iterator> #endif +#include <cmext/algorithm> + +#include "cmsys/FStream.hxx" +#include "cmsys/Glob.hxx" +#include "cmsys/RegularExpression.hxx" + #include "cm_sys_stat.h" #include "cmAlgorithms.h" @@ -56,6 +71,8 @@ // include the generator #if defined(_WIN32) && !defined(__CYGWIN__) # if !defined(CMAKE_BOOT_MINGW) +# include <cmext/memory> + # include "cmGlobalBorlandMakefileGenerator.h" # include "cmGlobalJOMMakefileGenerator.h" # include "cmGlobalNMakeMakefileGenerator.h" @@ -106,19 +123,6 @@ # include <sys/time.h> #endif -#include <algorithm> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <initializer_list> -#include <iostream> -#include <sstream> -#include <utility> - -#include "cmsys/FStream.hxx" -#include "cmsys/Glob.hxx" -#include "cmsys/RegularExpression.hxx" - namespace { #if !defined(CMAKE_BOOTSTRAP) @@ -201,14 +205,7 @@ cmake::cmake(Role role, cmState::Mode mode) } } -cmake::~cmake() -{ - if (this->GlobalGenerator) { - delete this->GlobalGenerator; - this->GlobalGenerator = nullptr; - } - cmDeleteAll(this->Generators); -} +cmake::~cmake() = default; #if !defined(CMAKE_BOOTSTRAP) Json::Value cmake::ReportVersionJson() const @@ -330,9 +327,8 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) } } } else { - std::cerr << "Parse error in command line argument: " << arg << "\n" - << "Should be: VAR:type=value\n"; - cmSystemTools::Error("No cmake script provided."); + cmSystemTools::Error("Parse error in command line argument: " + arg + + "\n" + "Should be: VAR:type=value\n"); return false; } } else if (cmHasLiteralPrefix(arg, "-W")) { @@ -393,7 +389,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) } } cmsys::RegularExpression regex( - cmsys::Glob::PatternToRegex(entryPattern, true, true).c_str()); + cmsys::Glob::PatternToRegex(entryPattern, true, true)); // go through all cache entries and collect the vars which will be // removed std::vector<std::string> entriesToDelete; @@ -422,7 +418,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) return false; } } - std::cout << "loading initial cache file " << path << "\n"; + cmSystemTools::Stdout("loading initial cache file " + path + "\n"); // Resolve script path specified on command line relative to $PWD. path = cmSystemTools::CollapseFullPath(path); this->ReadListFile(args, path); @@ -462,12 +458,12 @@ void cmake::ReadListFile(const std::vector<std::string>& args, { // if a generator was not yet created, temporarily create one cmGlobalGenerator* gg = this->GetGlobalGenerator(); - bool created = false; // if a generator was not specified use a generic one + std::unique_ptr<cmGlobalGenerator> gen; if (!gg) { - gg = new cmGlobalGenerator(this); - created = true; + gen = cm::make_unique<cmGlobalGenerator>(this); + gg = gen.get(); } // read in the list file to fill the cache @@ -489,11 +485,6 @@ void cmake::ReadListFile(const std::vector<std::string>& args, cmSystemTools::Error("Error processing file: " + path); } } - - // free generic one if generated - if (created) { - delete gg; - } } bool cmake::FindPackage(const std::vector<std::string>& args) @@ -501,9 +492,7 @@ bool cmake::FindPackage(const std::vector<std::string>& args) this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory()); this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory()); - // if a generator was not yet created, temporarily create one - cmGlobalGenerator* gg = new cmGlobalGenerator(this); - this->SetGlobalGenerator(gg); + this->SetGlobalGenerator(cm::make_unique<cmGlobalGenerator>(this)); cmStateSnapshot snapshot = this->GetCurrentSnapshot(); snapshot.GetDirectory().SetCurrentBinary( @@ -512,8 +501,9 @@ bool cmake::FindPackage(const std::vector<std::string>& args) cmSystemTools::GetCurrentWorkingDirectory()); // read in the list file to fill the cache snapshot.SetDefaultDefinitions(); - cmMakefile* mf = new cmMakefile(gg, snapshot); - gg->AddMakefile(mf); + auto mfu = cm::make_unique<cmMakefile>(this->GetGlobalGenerator(), snapshot); + cmMakefile* mf = mfu.get(); + this->GlobalGenerator->AddMakefile(std::move(mfu)); mf->SetArgcArgv(args); @@ -538,8 +528,8 @@ bool cmake::FindPackage(const std::vector<std::string>& args) std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS"); std::vector<std::string> includeDirs = cmExpandedList(includes); - gg->CreateGenerationObjects(); - cmLocalGenerator* lg = gg->LocalGenerators[0]; + this->GlobalGenerator->CreateGenerationObjects(); + const auto& lg = this->GlobalGenerator->LocalGenerators[0]; std::string includeFlags = lg->GetIncludeFlags(includeDirs, nullptr, language); @@ -549,7 +539,7 @@ bool cmake::FindPackage(const std::vector<std::string>& args) const char* targetName = "dummy"; std::vector<std::string> srcs; cmTarget* tgt = mf->AddExecutable(targetName, srcs, true); - tgt->SetProperty("LINKER_LANGUAGE", language.c_str()); + tgt->SetProperty("LINKER_LANGUAGE", language); std::string libs = mf->GetSafeDefinition("PACKAGE_LIBRARIES"); std::vector<std::string> libList = cmExpandedList(libs); @@ -565,8 +555,9 @@ bool cmake::FindPackage(const std::vector<std::string>& args) std::string linkPath; std::string flags; std::string linkFlags; - gg->CreateGenerationObjects(); - cmGeneratorTarget* gtgt = gg->FindGeneratorTarget(tgt->GetName()); + this->GlobalGenerator->CreateGenerationObjects(); + cmGeneratorTarget* gtgt = + this->GlobalGenerator->FindGeneratorTarget(tgt->GetName()); cmLocalGenerator* lg = gtgt->GetLocalGenerator(); cmLinkLineComputer linkLineComputer(lg, lg->GetStateSnapshot().GetDirectory()); @@ -586,10 +577,6 @@ bool cmake::FindPackage(const std::vector<std::string>& args) }*/ } - // free generic one if generated - // this->SetGlobalGenerator(0); // setting 0-pointer is not possible - // delete gg; // this crashes inside the cmake instance - return packageFound; } @@ -676,6 +663,8 @@ void cmake::SetArgs(const std::vector<std::string>& args) } else if ((i < args.size() - 1) && (arg.find("--check-stamp-list", 0) == 0)) { this->CheckStampList = args[++i]; + } else if (arg == "--regenerate-during-build") { + this->RegenerateDuringBuild = true; } #if defined(CMAKE_HAVE_VS_GENERATORS) else if ((i < args.size() - 1) && @@ -735,6 +724,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) return; } this->SetLogLevel(logLevel); + this->LogLevelWasSetViaCLI = true; } else if (arg.find("--loglevel=", 0) == 0) { // This is supported for backward compatibility. This option only // appeared in the 3.15.x release series and was renamed to @@ -746,10 +736,25 @@ void cmake::SetArgs(const std::vector<std::string>& args) return; } this->SetLogLevel(logLevel); + this->LogLevelWasSetViaCLI = true; + } else if (arg == "--log-context") { + this->SetShowLogContext(true); + } else if (arg.find("--debug-find", 0) == 0) { + std::cout << "Running with debug output on for the `find` commands.\n"; + this->SetDebugFindOutputOn(true); } else if (arg.find("--trace-expand", 0) == 0) { std::cout << "Running with expanded trace output on.\n"; this->SetTrace(true); this->SetTraceExpand(true); + } else if (arg.find("--trace-format=", 0) == 0) { + this->SetTrace(true); + const auto traceFormat = + StringToTraceFormat(arg.substr(strlen("--trace-format="))); + if (traceFormat == TraceFormat::TRACE_UNDEFINED) { + cmSystemTools::Error("Invalid format specified for --trace-format"); + return; + } + this->SetTraceFormat(traceFormat); } else if (arg.find("--trace-source=", 0) == 0) { std::string file = arg.substr(strlen("--trace-source=")); cmSystemTools::ConvertToUnixSlashes(file); @@ -821,7 +826,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) } value = args[i]; } - cmGlobalGenerator* gen = this->CreateGlobalGenerator(value); + auto gen = this->CreateGlobalGenerator(value); if (!gen) { std::string kdevError; if (value.find("KDevelop3", 0) != std::string::npos) { @@ -833,7 +838,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) this->PrintGeneratorList(); return; } - this->SetGlobalGenerator(gen); + this->SetGlobalGenerator(std::move(gen)); } // no option assume it is the path to the source or an existing build else { @@ -890,6 +895,23 @@ cmake::LogLevel cmake::StringToLogLevel(const std::string& levelStr) return (it != levels.cend()) ? it->second : LogLevel::LOG_UNDEFINED; } +cmake::TraceFormat cmake::StringToTraceFormat(const std::string& traceStr) +{ + using TracePair = std::pair<std::string, TraceFormat>; + static const std::vector<TracePair> levels = { + { "human", TraceFormat::TRACE_HUMAN }, + { "json-v1", TraceFormat::TRACE_JSON_V1 }, + }; + + const auto traceStrLowCase = cmSystemTools::LowerCase(traceStr); + + const auto it = std::find_if(levels.cbegin(), levels.cend(), + [&traceStrLowCase](const TracePair& p) { + return p.first == traceStrLowCase; + }); + return (it != levels.cend()) ? it->second : TraceFormat::TRACE_UNDEFINED; +} + void cmake::SetTraceFile(const std::string& file) { this->TraceFile.close(); @@ -904,6 +926,48 @@ void cmake::SetTraceFile(const std::string& file) std::cout << "Trace will be written to " << file << "\n"; } +void cmake::PrintTraceFormatVersion() +{ + if (!this->GetTrace()) { + return; + } + + std::string msg; + + switch (this->GetTraceFormat()) { + case TraceFormat::TRACE_JSON_V1: { +#ifndef CMAKE_BOOTSTRAP + Json::Value val; + Json::Value version; + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + version["major"] = 1; + version["minor"] = 0; + val["version"] = version; + msg = Json::writeString(builder, val); +#endif + break; + } + case TraceFormat::TRACE_HUMAN: + msg = ""; + break; + case TraceFormat::TRACE_UNDEFINED: + msg = "INTERNAL ERROR: Trace format is TRACE_UNDEFINED"; + break; + } + + if (msg.empty()) { + return; + } + + auto& f = this->GetTraceFile(); + if (f) { + f << msg << '\n'; + } else { + cmSystemTools::Message(msg); + } +} + void cmake::SetDirectoriesFromFile(const std::string& arg) { // Check if the argument refers to a CMakeCache.txt or @@ -1042,11 +1106,11 @@ void cmake::AddDefaultExtraGenerators() void cmake::GetRegisteredGenerators(std::vector<GeneratorInfo>& generators, bool includeNamesWithPlatform) const { - for (cmGlobalGeneratorFactory* gen : this->Generators) { + for (const auto& gen : this->Generators) { std::vector<std::string> names = gen->GetGeneratorNames(); if (includeNamesWithPlatform) { - cmAppend(names, gen->GetGeneratorNamesWithPlatform()); + cm::append(names, gen->GetGeneratorNamesWithPlatform()); } for (std::string const& name : names) { @@ -1091,7 +1155,8 @@ void cmake::GetRegisteredGenerators(std::vector<GeneratorInfo>& generators, } } -static std::pair<cmExternalMakefileProjectGenerator*, std::string> +static std::pair<std::unique_ptr<cmExternalMakefileProjectGenerator>, + std::string> createExtraGenerator( const std::vector<cmExternalMakefileProjectGeneratorFactory*>& in, const std::string& name) @@ -1114,15 +1179,17 @@ createExtraGenerator( return { nullptr, name }; } -cmGlobalGenerator* cmake::CreateGlobalGenerator(const std::string& gname) +std::unique_ptr<cmGlobalGenerator> cmake::CreateGlobalGenerator( + const std::string& gname) { - std::pair<cmExternalMakefileProjectGenerator*, std::string> extra = - createExtraGenerator(this->ExtraGenerators, gname); - cmExternalMakefileProjectGenerator* extraGenerator = extra.first; - const std::string name = extra.second; + std::pair<std::unique_ptr<cmExternalMakefileProjectGenerator>, std::string> + extra = createExtraGenerator(this->ExtraGenerators, gname); + std::unique_ptr<cmExternalMakefileProjectGenerator>& extraGenerator = + extra.first; + const std::string& name = extra.second; - cmGlobalGenerator* generator = nullptr; - for (cmGlobalGeneratorFactory* g : this->Generators) { + std::unique_ptr<cmGlobalGenerator> generator; + for (const auto& g : this->Generators) { generator = g->CreateGlobalGenerator(name, this); if (generator) { break; @@ -1130,9 +1197,7 @@ cmGlobalGenerator* cmake::CreateGlobalGenerator(const std::string& gname) } if (generator) { - generator->SetExternalMakefileProjectGenerator(extraGenerator); - } else { - delete extraGenerator; + generator->SetExternalMakefileProjectGenerator(std::move(extraGenerator)); } return generator; @@ -1184,15 +1249,13 @@ std::string cmake::FindCacheFile(const std::string& binaryDir) return cachePath; } -void cmake::SetGlobalGenerator(cmGlobalGenerator* gg) +void cmake::SetGlobalGenerator(std::unique_ptr<cmGlobalGenerator> gg) { if (!gg) { cmSystemTools::Error("Error SetGlobalGenerator called with null"); return; } - // delete the old generator if (this->GlobalGenerator) { - delete this->GlobalGenerator; // restore the original environment variables CXX and CC // Restore CC std::string env = "CC="; @@ -1208,7 +1271,7 @@ void cmake::SetGlobalGenerator(cmGlobalGenerator* gg) } // set the new - this->GlobalGenerator = gg; + this->GlobalGenerator = std::move(gg); // set the global flag for unix style paths on cmSystemTools as soon as // the generator is set. This allows gmake to be used on windows. @@ -1571,7 +1634,7 @@ int cmake::ActualConfigure() } } - cmMakefile* mf = this->GlobalGenerator->GetMakefiles()[0]; + auto& mf = this->GlobalGenerator->GetMakefiles()[0]; if (mf->IsOn("CTEST_USE_LAUNCHERS") && !this->State->GetGlobalProperty("RULE_LAUNCH_COMPILE")) { cmSystemTools::Error( @@ -1592,13 +1655,12 @@ int cmake::ActualConfigure() std::unique_ptr<cmGlobalGenerator> cmake::EvaluateDefaultGlobalGenerator() { if (!this->EnvironmentGenerator.empty()) { - cmGlobalGenerator* gen = - this->CreateGlobalGenerator(this->EnvironmentGenerator); + auto gen = this->CreateGlobalGenerator(this->EnvironmentGenerator); if (!gen) { cmSystemTools::Error("CMAKE_GENERATOR was set but the specified " "generator doesn't exist. Using CMake default."); } else { - return std::unique_ptr<cmGlobalGenerator>(gen); + return gen; } } #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW) @@ -1648,13 +1710,14 @@ std::unique_ptr<cmGlobalGenerator> cmake::EvaluateDefaultGlobalGenerator() } } } - cmGlobalGenerator* gen = this->CreateGlobalGenerator(found); + auto gen = this->CreateGlobalGenerator(found); if (!gen) { - gen = new cmGlobalNMakeMakefileGenerator(this); + gen = cm::make_unique<cmGlobalNMakeMakefileGenerator>(this); } - return std::unique_ptr<cmGlobalGenerator>(gen); + return std::unique_ptr<cmGlobalGenerator>(std::move(gen)); #else - return cm::make_unique<cmGlobalUnixMakefileGenerator3>(this); + return std::unique_ptr<cmGlobalGenerator>( + cm::make_unique<cmGlobalUnixMakefileGenerator3>(this)); #endif } @@ -1665,7 +1728,7 @@ void cmake::CreateDefaultGlobalGenerator() // This print could be unified for all platforms std::cout << "-- Building for: " << gen->GetName() << "\n"; #endif - this->SetGlobalGenerator(gen.release()); + this->SetGlobalGenerator(std::move(gen)); } void cmake::PreLoadCMakeFiles() @@ -1696,6 +1759,11 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure) return -1; } + // Log the trace format version to the desired output + if (this->GetTrace()) { + this->PrintTraceFormatVersion(); + } + // If we are given a stamp list file check if it is really out of date. if (!this->CheckStampList.empty() && cmakeCheckStampList(this->CheckStampList)) { @@ -1763,10 +1831,11 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure) cmSystemTools::Message("CMake Configure step failed. " "Build files cannot be regenerated correctly. " "Attempting to stop IDE build."); - cmGlobalVisualStudioGenerator* gg = - static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator); - gg->CallVisualStudioMacro(cmGlobalVisualStudioGenerator::MacroStop, - this->VSSolutionFile); + cmGlobalVisualStudioGenerator& gg = + cm::static_reference_cast<cmGlobalVisualStudioGenerator>( + this->GlobalGenerator); + gg.CallVisualStudioMacro(cmGlobalVisualStudioGenerator::MacroStop, + this->VSSolutionFile); } #endif return ret; @@ -1916,6 +1985,7 @@ void cmake::AddDefaultGenerators() this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory()); # endif this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory()); + this->Generators.push_back(cmGlobalNinjaMultiGenerator::NewFactory()); #endif #if defined(CMAKE_USE_WMAKE) this->Generators.push_back(cmGlobalWatcomWMakeGenerator::NewFactory()); @@ -2021,7 +2091,7 @@ void cmake::AppendGlobalGeneratorsDocumentation( const std::string defaultName = defaultGenerator->GetName(); bool foundDefaultOne = false; - for (cmGlobalGeneratorFactory* g : this->Generators) { + for (const auto& g : this->Generators) { cmDocumentationEntry e; g->GetDocumentation(e); if (!foundDefaultOne && cmHasPrefix(e.Name, defaultName)) { @@ -2161,12 +2231,12 @@ int cmake::CheckBuildSystem() } // Create the generator and use it to clear the dependencies. - std::unique_ptr<cmGlobalGenerator> ggd( - this->CreateGlobalGenerator(genName)); + std::unique_ptr<cmGlobalGenerator> ggd = + this->CreateGlobalGenerator(genName); if (ggd) { cm.GetCurrentSnapshot().SetDefaultDefinitions(); cmMakefile mfd(ggd.get(), cm.GetCurrentSnapshot()); - std::unique_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator(&mfd)); + auto lgd = ggd->CreateLocalGenerator(&mfd); lgd->ClearDependencies(&mfd, verbose); } } @@ -2287,7 +2357,7 @@ void cmake::MarkCliAsUsed(const std::string& variable) void cmake::GenerateGraphViz(const std::string& fileName) const { #ifndef CMAKE_BOOTSTRAP - cmGraphVizWriter gvWriter(this->GetGlobalGenerator()); + cmGraphVizWriter gvWriter(fileName, this->GetGlobalGenerator()); std::string settingsFile = cmStrCat(this->GetHomeOutputDirectory(), "/CMakeGraphVizOptions.cmake"); @@ -2295,9 +2365,8 @@ void cmake::GenerateGraphViz(const std::string& fileName) const cmStrCat(this->GetHomeDirectory(), "/CMakeGraphVizOptions.cmake"); gvWriter.ReadSettings(settingsFile, fallbackSettingsFile); - gvWriter.WritePerTargetFiles(fileName); - gvWriter.WriteTargetDependersFiles(fileName); - gvWriter.WriteGlobalFile(fileName); + + gvWriter.Write(); #endif } @@ -2307,7 +2376,7 @@ void cmake::SetProperty(const std::string& prop, const char* value) this->State->SetGlobalProperty(prop, value); } -void cmake::AppendProperty(const std::string& prop, const char* value, +void cmake::AppendProperty(const std::string& prop, const std::string& value, bool asString) { this->State->AppendGlobalProperty(prop, value, asString); @@ -2376,12 +2445,12 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) } value = args[i]; } - cmGlobalGenerator* gen = this->CreateGlobalGenerator(value); + auto gen = this->CreateGlobalGenerator(value); if (!gen) { cmSystemTools::Error("Could not create named generator " + value); this->PrintGeneratorList(); } else { - this->SetGlobalGenerator(gen); + this->SetGlobalGenerator(std::move(gen)); } } // no option assume it is the output file @@ -2593,26 +2662,37 @@ int cmake::Build(int jobs, const std::string& dir, std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n"; return 1; } - cmGlobalGenerator* gen = this->CreateGlobalGenerator(cachedGenerator); + auto gen = this->CreateGlobalGenerator(cachedGenerator); if (!gen) { std::cerr << "Error: could create CMAKE_GENERATOR \"" << cachedGenerator << "\"\n"; return 1; } - this->SetGlobalGenerator(gen); + this->SetGlobalGenerator(std::move(gen)); const char* cachedGeneratorInstance = this->State->GetCacheEntryValue("CMAKE_GENERATOR_INSTANCE"); if (cachedGeneratorInstance) { - cmMakefile mf(gen, this->GetCurrentSnapshot()); - if (!gen->SetGeneratorInstance(cachedGeneratorInstance, &mf)) { + cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot()); + if (!this->GlobalGenerator->SetGeneratorInstance(cachedGeneratorInstance, + &mf)) { return 1; } } const char* cachedGeneratorPlatform = this->State->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM"); if (cachedGeneratorPlatform) { - cmMakefile mf(gen, this->GetCurrentSnapshot()); - if (!gen->SetGeneratorPlatform(cachedGeneratorPlatform, &mf)) { + cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot()); + if (!this->GlobalGenerator->SetGeneratorPlatform(cachedGeneratorPlatform, + &mf)) { + return 1; + } + } + const char* cachedGeneratorToolset = + this->State->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET"); + if (cachedGeneratorToolset) { + cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot()); + if (!this->GlobalGenerator->SetGeneratorToolset(cachedGeneratorToolset, + true, &mf)) { return 1; } } @@ -2687,10 +2767,15 @@ int cmake::Build(int jobs, const std::string& dir, } #endif - gen->PrintBuildCommandAdvice(std::cerr, jobs); - return gen->Build(jobs, "", dir, projName, targets, output, "", config, - clean, false, verbose, cmDuration::zero(), - cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions); + if (!this->GlobalGenerator->ReadCacheEntriesForBuild(*this->State)) { + return 1; + } + + this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, jobs); + return this->GlobalGenerator->Build( + jobs, "", dir, projName, targets, output, "", config, clean, false, + verbose, cmDuration::zero(), cmSystemTools::OUTPUT_PASSTHROUGH, + nativeOptions); } bool cmake::Open(const std::string& dir, bool dryRun) @@ -2718,8 +2803,8 @@ bool cmake::Open(const std::string& dir, bool dryRun) cmExternalMakefileProjectGenerator::CreateFullGeneratorName( genName, extraGenName ? *extraGenName : ""); - std::unique_ptr<cmGlobalGenerator> gen( - this->CreateGlobalGenerator(fullName)); + std::unique_ptr<cmGlobalGenerator> gen = + this->CreateGlobalGenerator(fullName); if (!gen) { std::cerr << "Error: could create CMAKE_GENERATOR \"" << fullName << "\"\n"; diff --git a/Source/cmake.h b/Source/cmake.h index 687c105..35425ec 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -5,12 +5,15 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <functional> #include <map> #include <memory> #include <set> +#include <stack> #include <string> #include <unordered_set> +#include <utility> #include <vector> #include "cmGeneratedFileStream.h" @@ -110,6 +113,14 @@ public: LOG_TRACE }; + /** \brief Define supported trace formats **/ + enum TraceFormat + { + TRACE_UNDEFINED, + TRACE_HUMAN, + TRACE_JSON_V1, + }; + struct GeneratorInfo { std::string name; @@ -202,21 +213,25 @@ public: void PreLoadCMakeFiles(); //! Create a GlobalGenerator - cmGlobalGenerator* CreateGlobalGenerator(const std::string& name); + std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( + const std::string& name); //! Return the global generator assigned to this instance of cmake - cmGlobalGenerator* GetGlobalGenerator() { return this->GlobalGenerator; } + cmGlobalGenerator* GetGlobalGenerator() + { + return this->GlobalGenerator.get(); + } //! Return the global generator assigned to this instance of cmake, const const cmGlobalGenerator* GetGlobalGenerator() const { - return this->GlobalGenerator; + return this->GlobalGenerator.get(); } //! Return the full path to where the CMakeCache.txt file should be. static std::string FindCacheFile(const std::string& binaryDir); //! Return the global generator assigned to this instance of cmake - void SetGlobalGenerator(cmGlobalGenerator*); + void SetGlobalGenerator(std::unique_ptr<cmGlobalGenerator>); //! Get the names of the current registered generators void GetRegisteredGenerators(std::vector<GeneratorInfo>& generators, @@ -344,7 +359,7 @@ public: //! Set/Get a property of this target file void SetProperty(const std::string& prop, const char* value); - void AppendProperty(const std::string& prop, const char* value, + void AppendProperty(const std::string& prop, const std::string& value, bool asString = false); const char* GetProperty(const std::string& prop); bool GetPropertyAsBool(const std::string& prop); @@ -380,20 +395,52 @@ public: */ cmFileTimeCache* GetFileTimeCache() { return this->FileTimeCache.get(); } + bool WasLogLevelSetViaCLI() const { return this->LogLevelWasSetViaCLI; } + //! Get the selected log level for `message()` commands during the cmake run. LogLevel GetLogLevel() const { return this->MessageLogLevel; } void SetLogLevel(LogLevel level) { this->MessageLogLevel = level; } static LogLevel StringToLogLevel(const std::string& levelStr); + static TraceFormat StringToTraceFormat(const std::string& levelStr); + + bool HasCheckInProgress() const + { + return !this->CheckInProgressMessages.empty(); + } + std::size_t GetCheckInProgressSize() const + { + return this->CheckInProgressMessages.size(); + } + std::string GetTopCheckInProgressMessage() + { + auto message = this->CheckInProgressMessages.top(); + this->CheckInProgressMessages.pop(); + return message; + } + void PushCheckInProgressMessage(std::string message) + { + this->CheckInProgressMessages.emplace(std::move(message)); + } + + //! Should `message` command display context. + bool GetShowLogContext() const { return this->LogContext; } + void SetShowLogContext(bool b) { this->LogContext = b; } //! Do we want debug output during the cmake run. bool GetDebugOutput() { return this->DebugOutput; } void SetDebugOutputOn(bool b) { this->DebugOutput = b; } + //! Do we want debug output from the find commands during the cmake run. + bool GetDebugFindOutput() { return this->DebugFindOutput; } + void SetDebugFindOutputOn(bool b) { this->DebugFindOutput = b; } + //! Do we want trace output during the cmake run. - bool GetTrace() { return this->Trace; } + bool GetTrace() const { return this->Trace; } void SetTrace(bool b) { this->Trace = b; } - bool GetTraceExpand() { return this->TraceExpand; } + bool GetTraceExpand() const { return this->TraceExpand; } void SetTraceExpand(bool b) { this->TraceExpand = b; } + TraceFormat GetTraceFormat() const { return this->TraceFormatVar; } + void SetTraceFormat(TraceFormat f) { this->TraceFormatVar = f; } void AddTraceSource(std::string const& file) { this->TraceOnlyThisSources.push_back(file); @@ -404,6 +451,7 @@ public: } cmGeneratedFileStream& GetTraceFile() { return this->TraceFile; } void SetTraceFile(std::string const& file); + void PrintTraceFormatVersion(); bool GetWarnUninitialized() { return this->WarnUninitialized; } void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; } @@ -499,11 +547,14 @@ public: } cmStateSnapshot GetCurrentSnapshot() const { return this->CurrentSnapshot; } + bool GetRegenerateDuringBuild() const { return this->RegenerateDuringBuild; } + protected: void RunCheckForUnusedVariables(); int HandleDeleteCacheVariables(const std::string& var); - using RegisteredGeneratorsVector = std::vector<cmGlobalGeneratorFactory*>; + using RegisteredGeneratorsVector = + std::vector<std::unique_ptr<cmGlobalGeneratorFactory>>; RegisteredGeneratorsVector Generators; using RegisteredExtraGeneratorsVector = std::vector<cmExternalMakefileProjectGeneratorFactory*>; @@ -513,7 +564,6 @@ protected: void AddDefaultGenerators(); void AddDefaultExtraGenerators(); - cmGlobalGenerator* GlobalGenerator = nullptr; std::map<std::string, DiagLevel> DiagLevels; std::string GeneratorInstance; std::string GeneratorPlatform; @@ -549,8 +599,10 @@ private: ProgressCallbackType ProgressCallback; WorkingMode CurrentWorkingMode = NORMAL_MODE; bool DebugOutput = false; + bool DebugFindOutput = false; bool Trace = false; bool TraceExpand = false; + TraceFormat TraceFormatVar = TRACE_HUMAN; cmGeneratedFileStream TraceFile; bool WarnUninitialized = false; bool WarnUnused = false; @@ -571,6 +623,7 @@ private: FileExtensions FortranFileExtensions; bool ClearBuildSystem = false; bool DebugTryCompile = false; + bool RegenerateDuringBuild = false; std::unique_ptr<cmFileTimeCache> FileTimeCache; std::string GraphVizFile; InstalledFilesMap InstalledFiles; @@ -587,6 +640,12 @@ private: std::vector<std::string> TraceOnlyThisSources; LogLevel MessageLogLevel = LogLevel::LOG_STATUS; + bool LogLevelWasSetViaCLI = false; + bool LogContext = false; + + std::stack<std::string> CheckInProgressMessages; + + std::unique_ptr<cmGlobalGenerator> GlobalGenerator; void UpdateConversionPathTable(); @@ -714,4 +773,11 @@ private: FOR_EACH_CXX11_FEATURE(F) \ FOR_EACH_CXX14_FEATURE(F) +#define FOR_EACH_CUDA_FEATURE(F) \ + F(cuda_std_03) \ + F(cuda_std_11) \ + F(cuda_std_14) \ + F(cuda_std_17) \ + F(cuda_std_20) + #endif diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 6d3e6ee..494d5d9 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -1,7 +1,16 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmAlgorithms.h" +#include <cassert> +#include <cctype> +#include <climits> +#include <cstring> +#include <iostream> +#include <string> +#include <vector> + +#include <cmext/algorithm> + #include "cmDocumentationEntry.h" // IWYU pragma: keep #include "cmGlobalGenerator.h" #include "cmMakefile.h" @@ -24,14 +33,6 @@ # include "cmsys/ConsoleBuf.hxx" #endif -#include <cassert> -#include <cctype> -#include <climits> -#include <cstring> -#include <iostream> -#include <string> -#include <vector> - namespace { #ifndef CMAKE_BOOTSTRAP const char* cmDocumentationName[][2] = { @@ -73,12 +74,15 @@ const char* cmDocumentationOptions[][2] = { { "--log-level=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>", "Set the verbosity of messages from CMake files. " "--loglevel is also accepted for backward compatibility reasons." }, + { "--log-context", "Prepend log messages with context, if given" }, { "--debug-trycompile", "Do not delete the try_compile build tree. Only " "useful on one try_compile at a time." }, { "--debug-output", "Put cmake in a debug mode." }, + { "--debug-find", "Put cmake find in a debug mode." }, { "--trace", "Put cmake in trace mode." }, { "--trace-expand", "Put cmake in trace mode with variable expansion." }, + { "--trace-format=<human|json-v1>", "Set the output format of the trace." }, { "--trace-source=<file>", "Trace only this CMake file/module. Multiple options allowed." }, { "--trace-redirect=<file>", @@ -99,7 +103,7 @@ int do_command(int ac, char const* const* av) std::vector<std::string> args; args.reserve(ac - 1); args.emplace_back(av[0]); - cmAppend(args, av + 2, av + ac); + cm::append(args, av + 2, av + ac); return cmcmd::ExecuteCMakeCommand(args); } @@ -346,7 +350,7 @@ int do_build(int ac, char const* const* av) #else int jobs = cmake::NO_BUILD_PARALLEL_LEVEL; std::vector<std::string> targets; - std::string config = "Debug"; + std::string config; std::string dir; std::vector<std::string> nativeOptions; bool cleanFirst = false; @@ -682,7 +686,6 @@ int main(int ac, char const* const* av) ac = args.argc(); av = args.argv(); - cmSystemTools::EnableMSVCDebugHook(); cmSystemTools::InitializeLibUV(); cmSystemTools::FindCMakeResources(av[0]); if (ac > 1) { diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index d05e3c8..7eeb97f 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -2,6 +2,12 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmcmd.h" +#include <cmext/algorithm> + +#include <fcntl.h> + +#include "cm_uv.h" + #include "cmAlgorithms.h" #include "cmDuration.h" #include "cmGlobalGenerator.h" @@ -15,22 +21,22 @@ #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmUVProcessChain.h" #include "cmUtils.hxx" #include "cmVersion.h" #include "cmake.h" #if !defined(CMAKE_BOOTSTRAP) # include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback. +# include "cmFileTime.h" # include "cmServer.h" # include "cmServerConnection.h" + +# include "bindexplib.h" #endif #if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32) # include "cmsys/ConsoleBuf.hxx" - -# include "cmFileTime.h" - -# include "bindexplib.h" #endif #if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32) && !defined(__CYGWIN__) @@ -107,10 +113,12 @@ void CMakeCommandUsage(const char* program) << " sha384sum <file>... - create SHA384 checksum of files\n" << " sha512sum <file>... - create SHA512 checksum of files\n" << " remove [-f] <file>... - remove the file(s), use -f to force " - "it\n" - << " remove_directory <dir>... - remove directories and their contents\n" + "it (deprecated: use rm instead)\n" + << " remove_directory <dir>... - remove directories and their contents (deprecated: use rm instead)\n" << " rename oldname newname - rename a file or directory " "(on one volume)\n" + << " rm [-rRf] <file/dir>... - remove files or directories, use -f to " + "force it, r or R to remove directories and their contents recursively\n" << " server - start cmake in server mode\n" << " sleep <number>... - sleep for given number of seconds\n" << " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n" @@ -172,6 +180,24 @@ static bool cmTarFilesFrom(std::string const& file, return true; } +static bool cmRemoveDirectory(const std::string& dir, bool recursive = true) +{ + if (cmSystemTools::FileIsSymlink(dir)) { + if (!cmSystemTools::RemoveFile(dir)) { + std::cerr << "Error removing directory symlink \"" << dir << "\".\n"; + return false; + } + } else if (!recursive) { + std::cerr << "Error removing directory \"" << dir + << "\" without recursive option.\n"; + return false; + } else if (!cmSystemTools::RemoveADirectory(dir)) { + std::cerr << "Error removing directory \"" << dir << "\".\n"; + return false; + } + return true; +} + static int HandleIWYU(const std::string& runCmd, const std::string& /* sourceFile */, const std::vector<std::string>& orig_cmd) @@ -179,7 +205,7 @@ static int HandleIWYU(const std::string& runCmd, // Construct the iwyu command line by taking what was given // and adding all the arguments we give to the compiler. std::vector<std::string> iwyu_cmd = cmExpandedList(runCmd, true); - cmAppend(iwyu_cmd, orig_cmd.begin() + 1, orig_cmd.end()); + cm::append(iwyu_cmd, orig_cmd.begin() + 1, orig_cmd.end()); // Run the iwyu command line. Capture its stderr and hide its stdout. // Ignore its return code because the tool always returns non-zero. std::string stdErr; @@ -210,7 +236,7 @@ static int HandleTidy(const std::string& runCmd, const std::string& sourceFile, std::vector<std::string> tidy_cmd = cmExpandedList(runCmd, true); tidy_cmd.push_back(sourceFile); tidy_cmd.emplace_back("--"); - cmAppend(tidy_cmd, orig_cmd); + cm::append(tidy_cmd, orig_cmd); // Run the tidy command line. Capture its stdout and hide its stderr. std::string stdOut; @@ -561,11 +587,11 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) return 0; } -#if defined(_WIN32) && !defined(CMAKE_BOOTSTRAP) - else if (args[1] == "__create_def") { +#if !defined(CMAKE_BOOTSTRAP) + if (args[1] == "__create_def") { if (args.size() < 4) { std::cerr << "__create_def Usage: -E __create_def outfile.def " - "objlistfile [-nm=nm-path]\n"; + "objlistfile [--nm=nm-path]\n"; return 1; } cmsys::ifstream fin(args[3].c_str(), std::ios::in | std::ios::binary); @@ -592,7 +618,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) return 0; } } - FILE* fout = cmsys::SystemTools::Fopen(args[2].c_str(), "w+"); + FILE* fout = cmsys::SystemTools::Fopen(args[2], "w+"); if (!fout) { std::cerr << "could not open output .def file: " << args[2].c_str() << "\n"; @@ -706,14 +732,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) bool return_value = false; for (auto const& arg : cmMakeRange(args).advance(2)) { if (cmSystemTools::FileIsDirectory(arg)) { - if (cmSystemTools::FileIsSymlink(arg)) { - if (!cmSystemTools::RemoveFile(arg)) { - std::cerr << "Error removing directory symlink \"" << arg - << "\".\n"; - return_value = true; - } - } else if (!cmSystemTools::RemoveADirectory(arg)) { - std::cerr << "Error removing directory \"" << arg << "\".\n"; + if (!cmRemoveDirectory(arg)) { return_value = true; } } @@ -739,6 +758,65 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) return 0; } + // Remove directories or files with rm + if (args[1] == "rm" && args.size() > 2) { + // If an error occurs, we want to continue removing the remaining + // files/directories. + int return_value = 0; + bool force = false; + bool recursive = false; + bool doing_options = true; + bool at_least_one_file = false; + for (auto const& arg : cmMakeRange(args).advance(2)) { + if (doing_options && cmHasLiteralPrefix(arg, "-")) { + if (arg == "--") { + doing_options = false; + } + if (arg.find('f') != std::string::npos) { + force = true; + } + if (arg.find_first_of("rR") != std::string::npos) { + recursive = true; + } + if (arg.find_first_not_of("-frR") != std::string::npos) { + cmSystemTools::Error("Unknown -E rm argument: " + arg); + return 1; + } + } else { + if (arg.empty()) { + continue; + } + at_least_one_file = true; + // Complain if the -f option was not given and + // either file does not exist or + // file could not be removed and still exists + bool file_exists_or_forced_remove = cmSystemTools::FileExists(arg) || + cmSystemTools::FileIsSymlink(arg) || force; + if (cmSystemTools::FileIsDirectory(arg)) { + if (!cmRemoveDirectory(arg, recursive)) { + return_value = 1; + } + } else if ((!file_exists_or_forced_remove) || + (!cmSystemTools::RemoveFile(arg) && + cmSystemTools::FileExists(arg))) { + if (!file_exists_or_forced_remove) { + cmSystemTools::Error( + "File to remove does not exist and force is not set: " + arg); + } else { + cmSystemTools::Error("File can't be removed and still exist: " + + arg); + } + return_value = 1; + } + } + } + if (!at_least_one_file) { + cmSystemTools::Error("Missing file/directory to remove"); + return 1; + } + return return_value; + } + // Touch file if (args[1] == "touch" && args.size() > 2) { for (auto const& arg : cmMakeRange(args).advance(2)) { @@ -1007,13 +1085,13 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) cm.SetHomeDirectory(homeDir); cm.SetHomeOutputDirectory(homeOutDir); cm.GetCurrentSnapshot().SetDefaultDefinitions(); - if (cmGlobalGenerator* ggd = cm.CreateGlobalGenerator(gen)) { - cm.SetGlobalGenerator(ggd); + if (auto ggd = cm.CreateGlobalGenerator(gen)) { + cm.SetGlobalGenerator(std::move(ggd)); cmStateSnapshot snapshot = cm.GetCurrentSnapshot(); snapshot.GetDirectory().SetCurrentBinary(startOutDir); snapshot.GetDirectory().SetCurrentSource(startDir); - cmMakefile mf(ggd, snapshot); - std::unique_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator(&mf)); + cmMakefile mf(cm.GetGlobalGenerator(), snapshot); + auto lgd = cm.GetGlobalGenerator()->CreateLocalGenerator(&mf); // Actually scan dependencies. return lgd->UpdateDependencies(depInfo, verbose, color) ? 0 : 2; @@ -1056,6 +1134,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) return cmcmd::VisualStudioLink(args, 2); } + if (args[1] == "cmake_llvm_rc") { + return cmcmd::RunLLVMRC(args); + } + // Internal CMake color makefile support. if (args[1] == "cmake_echo_color") { return cmcmd::ExecuteEchoColor(args); @@ -1587,6 +1669,108 @@ int cmcmd::WindowsCEEnvironment(const char* version, const std::string& name) return -1; } +int cmcmd::RunPreprocessor(const std::vector<std::string>& command, + const std::string& intermediate_file) +{ + + cmUVProcessChainBuilder builder; + + uv_fs_t fs_req; + int preprocessedFile = + uv_fs_open(nullptr, &fs_req, intermediate_file.c_str(), O_CREAT | O_RDWR, + 0644, nullptr); + uv_fs_req_cleanup(&fs_req); + + builder + .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, + preprocessedFile) + .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR) + .AddCommand(command); + auto process = builder.Start(); + if (!process.Valid()) { + std::cerr << "Failed to start preprocessor."; + return 1; + } + if (!process.Wait()) { + std::cerr << "Failed to wait for preprocessor"; + return 1; + } + auto status = process.GetStatus(); + if (!status[0] || status[0]->ExitStatus != 0) { + return 1; + } + + return 0; +} + +int cmcmd::RunLLVMRC(std::vector<std::string> const& args) +{ + // The arguments are + // args[0] == <cmake-executable> + // args[1] == cmake_llvm_rc + // args[2] == intermediate_file + // args[3..n] == preprocess+args + // args[n+1] == -- + // args[n+2...] == llvm-rc+args + if (args.size() < 3) { + std::cerr << "Invalid cmake_llvm_rc arguments"; + return 1; + } + const std::string& intermediate_file = args[2]; + std::vector<std::string> preprocess; + std::vector<std::string> resource_compile; + std::vector<std::string>* pArgTgt = &preprocess; + for (std::string const& arg : cmMakeRange(args).advance(3)) { + if (arg == "--") { + pArgTgt = &resource_compile; + } else { + pArgTgt->push_back(arg); + } + } + if (preprocess.empty()) { + std::cerr << "Empty preprocessing command"; + return 1; + } + if (resource_compile.empty()) { + std::cerr << "Empty resource compilation command"; + return 1; + } + + auto result = RunPreprocessor(preprocess, intermediate_file); + if (result != 0) { + + cmSystemTools::RemoveFile(intermediate_file); + return result; + } + cmUVProcessChainBuilder builder; + + builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT) + .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR) + .AddCommand(resource_compile); + auto process = builder.Start(); + result = 0; + if (!process.Valid()) { + std::cerr << "Failed to start resource compiler."; + result = 1; + } else { + if (!process.Wait()) { + std::cerr << "Failed to wait for resource compiler"; + result = 1; + } + } + + cmSystemTools::RemoveFile(intermediate_file); + if (result != 0) { + return result; + } + auto status = process.GetStatus(); + if (!status[0] || status[0]->ExitStatus != 0) { + return 1; + } + + return 0; +} + class cmVSLink { int Type; @@ -1956,7 +2140,7 @@ int cmVSLink::RunMT(std::string const& out, bool notify) if (this->LinkGeneratesManifest) { mtCommand.push_back(this->LinkerManifestFile); } - cmAppend(mtCommand, this->UserManifests); + cm::append(mtCommand, this->UserManifests); mtCommand.push_back(out); if (notify) { // Add an undocumented option that enables a special return diff --git a/Source/cmcmd.h b/Source/cmcmd.h index 17f2f9a..5b6c813 100644 --- a/Source/cmcmd.h +++ b/Source/cmcmd.h @@ -31,6 +31,9 @@ protected: static int ExecuteLinkScript(std::vector<std::string> const& args); static int WindowsCEEnvironment(const char* version, const std::string& name); + static int RunPreprocessor(const std::vector<std::string>& command, + const std::string& intermediate_file); + static int RunLLVMRC(std::vector<std::string> const& args); static int VisualStudioLink(std::vector<std::string> const& args, int type); }; diff --git a/Source/ctest.cxx b/Source/ctest.cxx index 0d65902..fbdf75a 100644 --- a/Source/ctest.cxx +++ b/Source/ctest.cxx @@ -98,9 +98,12 @@ static const char* cmDocumentationOptions[][2] = { "Run a specific number of tests by number." }, { "-U, --union", "Take the Union of -I and -R" }, { "--rerun-failed", "Run only the tests that failed previously" }, - { "--repeat-until-fail <n>", - "Require each test to run <n> " - "times without failing in order to pass" }, + { "--repeat until-fail:<n>, --repeat-until-fail <n>", + "Require each test to run <n> times without failing in order to pass" }, + { "--repeat until-pass:<n>", + "Allow each test to run up to <n> times in order to pass" }, + { "--repeat after-timeout:<n>", + "Allow each test to run up to <n> times if it times out" }, { "--max-width <width>", "Set the max width for a test name to output" }, { "--interactive-debug-mode [0|1]", "Set the interactive mode to 0 or 1." }, { "--resource-spec-file <file>", "Set the resource spec file to use." }, @@ -141,6 +144,8 @@ static const char* cmDocumentationOptions[][2] = { { "--http1.0", "Submit using HTTP 1.0." }, { "--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 } }; @@ -161,7 +166,6 @@ int main(int argc, char const* const* argv) argv = encoding_args.argv(); cmSystemTools::DoNotInheritStdPipes(); - cmSystemTools::EnableMSVCDebugHook(); cmSystemTools::InitializeLibUV(); cmSystemTools::FindCMakeResources(argv[0]); diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 09bcdb9..5de2776 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -11,9 +11,9 @@ # be used. All classes are disabled by default. The CMake listfile # above this one configures the library as follows: # -# SET(KWSYS_NAMESPACE foosys) -# SET(KWSYS_USE_Directory 1) # Enable Directory class. -# SUBDIRS(kwsys) +# set(KWSYS_NAMESPACE foosys) +# set(KWSYS_USE_Directory 1) # Enable Directory class. +# add_subdirectory(kwsys) # # Optional settings are as follows: # @@ -39,8 +39,8 @@ # # Example: # -# SET(KWSYS_HEADER_ROOT ${PROJECT_BINARY_DIR}) -# INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}) +# set(KWSYS_HEADER_ROOT ${PROJECT_BINARY_DIR}) +# include_directories(${PROJECT_BINARY_DIR}) # # KWSYS_CXX_STANDARD = A value for CMAKE_CXX_STANDARD within KWSys. # Set to empty string to use no default value. @@ -65,11 +65,11 @@ # # Example: # -# SET(KWSYS_INSTALL_BIN_DIR bin) -# SET(KWSYS_INSTALL_LIB_DIR lib) -# SET(KWSYS_INSTALL_INCLUDE_DIR include) -# SET(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME Runtime) -# SET(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT Development) +# set(KWSYS_INSTALL_BIN_DIR bin) +# set(KWSYS_INSTALL_LIB_DIR lib) +# set(KWSYS_INSTALL_INCLUDE_DIR include) +# set(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME Runtime) +# set(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT Development) # Once configured, kwsys should be used as follows from C or C++ code: # @@ -86,33 +86,33 @@ # any outside mailing list and no documentation of the change will be # written. -CMAKE_MINIMUM_REQUIRED(VERSION 3.1 FATAL_ERROR) -FOREACH(p +cmake_minimum_required(VERSION 3.1 FATAL_ERROR) +foreach(p CMP0056 # CMake 3.2, Honor link flags in try_compile() source-file signature. CMP0063 # CMake 3.3, Honor visibility properties for all target types. CMP0067 # CMake 3.8, Honor language standard in try_compile source-file signature. CMP0069 # CMake 3.9, INTERPROCEDURAL_OPTIMIZATION is enforced when enabled. ) - IF(POLICY ${p}) - CMAKE_POLICY(SET ${p} NEW) - ENDIF() -ENDFOREACH() + if(POLICY ${p}) + cmake_policy(SET ${p} NEW) + endif() +endforeach() #----------------------------------------------------------------------------- # If a namespace is not specified, use "kwsys" and enable testing. # This should be the case only when kwsys is not included inside # another project and is being tested. -IF(NOT KWSYS_NAMESPACE) - SET(KWSYS_NAMESPACE "kwsys") - SET(KWSYS_STANDALONE 1) -ENDIF() +if(NOT KWSYS_NAMESPACE) + set(KWSYS_NAMESPACE "kwsys") + set(KWSYS_STANDALONE 1) +endif() #----------------------------------------------------------------------------- # The project name is that of the specified namespace. -PROJECT(${KWSYS_NAMESPACE}) +project(${KWSYS_NAMESPACE}) # Tell CMake how to follow dependencies of sources in this directory. -SET_PROPERTY(DIRECTORY +set_property(DIRECTORY PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM "KWSYS_HEADER(%)=<${KWSYS_NAMESPACE}/%>" ) @@ -131,229 +131,229 @@ elseif(NOT DEFINED CMAKE_CXX_STANDARD AND NOT DEFINED KWSYS_CXX_STANDARD) endif() # Select library components. -IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) - SET(KWSYS_ENABLE_C 1) +if(KWSYS_STANDALONE OR CMake_SOURCE_DIR) + set(KWSYS_ENABLE_C 1) # Enable all components. - SET(KWSYS_USE_Base64 1) - SET(KWSYS_USE_Directory 1) - SET(KWSYS_USE_DynamicLoader 1) - SET(KWSYS_USE_Encoding 1) - SET(KWSYS_USE_Glob 1) - SET(KWSYS_USE_MD5 1) - SET(KWSYS_USE_Process 1) - SET(KWSYS_USE_RegularExpression 1) - SET(KWSYS_USE_System 1) - SET(KWSYS_USE_SystemTools 1) - SET(KWSYS_USE_CommandLineArguments 1) - SET(KWSYS_USE_Terminal 1) - SET(KWSYS_USE_IOStream 1) - SET(KWSYS_USE_FStream 1) - SET(KWSYS_USE_String 1) - SET(KWSYS_USE_SystemInformation 1) - SET(KWSYS_USE_ConsoleBuf 1) -ENDIF() + set(KWSYS_USE_Base64 1) + set(KWSYS_USE_Directory 1) + set(KWSYS_USE_DynamicLoader 1) + set(KWSYS_USE_Encoding 1) + set(KWSYS_USE_Glob 1) + set(KWSYS_USE_MD5 1) + set(KWSYS_USE_Process 1) + set(KWSYS_USE_RegularExpression 1) + set(KWSYS_USE_System 1) + set(KWSYS_USE_SystemTools 1) + set(KWSYS_USE_CommandLineArguments 1) + set(KWSYS_USE_Terminal 1) + set(KWSYS_USE_IOStream 1) + set(KWSYS_USE_FStream 1) + set(KWSYS_USE_String 1) + set(KWSYS_USE_SystemInformation 1) + set(KWSYS_USE_ConsoleBuf 1) +endif() # Enforce component dependencies. -IF(KWSYS_USE_SystemTools) - SET(KWSYS_USE_Directory 1) - SET(KWSYS_USE_FStream 1) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_Glob) - SET(KWSYS_USE_Directory 1) - SET(KWSYS_USE_SystemTools 1) - SET(KWSYS_USE_RegularExpression 1) - SET(KWSYS_USE_FStream 1) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_Process) - SET(KWSYS_USE_System 1) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_SystemInformation) - SET(KWSYS_USE_Process 1) -ENDIF() -IF(KWSYS_USE_System) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_Directory) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_DynamicLoader) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_FStream) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_ConsoleBuf) - SET(KWSYS_USE_Encoding 1) -ENDIF() +if(KWSYS_USE_SystemTools) + set(KWSYS_USE_Directory 1) + set(KWSYS_USE_FStream 1) + set(KWSYS_USE_Encoding 1) +endif() +if(KWSYS_USE_Glob) + set(KWSYS_USE_Directory 1) + set(KWSYS_USE_SystemTools 1) + set(KWSYS_USE_RegularExpression 1) + set(KWSYS_USE_FStream 1) + set(KWSYS_USE_Encoding 1) +endif() +if(KWSYS_USE_Process) + set(KWSYS_USE_System 1) + set(KWSYS_USE_Encoding 1) +endif() +if(KWSYS_USE_SystemInformation) + set(KWSYS_USE_Process 1) +endif() +if(KWSYS_USE_System) + set(KWSYS_USE_Encoding 1) +endif() +if(KWSYS_USE_Directory) + set(KWSYS_USE_Encoding 1) +endif() +if(KWSYS_USE_DynamicLoader) + set(KWSYS_USE_Encoding 1) +endif() +if(KWSYS_USE_FStream) + set(KWSYS_USE_Encoding 1) +endif() +if(KWSYS_USE_ConsoleBuf) + set(KWSYS_USE_Encoding 1) +endif() # Specify default 8 bit encoding for Windows -IF(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE) - SET(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP) -ENDIF() +if(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE) + set(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP) +endif() # Enable testing if building standalone. -IF(KWSYS_STANDALONE) - INCLUDE(Dart) - MARK_AS_ADVANCED(BUILD_TESTING DART_ROOT TCL_TCLSH) - IF(BUILD_TESTING) - ENABLE_TESTING() - ENDIF() -ENDIF() +if(KWSYS_STANDALONE) + include(Dart) + mark_as_advanced(BUILD_TESTING DART_ROOT TCL_TCLSH) + if(BUILD_TESTING) + enable_testing() + endif() +endif() # Choose default shared/static build if not specified. -IF(NOT DEFINED KWSYS_BUILD_SHARED) - SET(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS}) -ENDIF() +if(NOT DEFINED KWSYS_BUILD_SHARED) + set(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS}) +endif() # Include helper macros. -INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformTests.cmake) -INCLUDE(CheckTypeSize) +include(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformTests.cmake) +include(CheckTypeSize) # Do full dependency headers. -INCLUDE_REGULAR_EXPRESSION("^.*$") +include_regular_expression("^.*$") # Use new KWSYS_INSTALL_*_DIR variable names to control installation. # Take defaults from the old names. Note that there was no old name # for the bin dir, so we take the old lib dir name so DLLs will be # installed in a compatible way for old code. -IF(NOT KWSYS_INSTALL_INCLUDE_DIR) - STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_INCLUDE_DIR +if(NOT KWSYS_INSTALL_INCLUDE_DIR) + string(REGEX REPLACE "^/" "" KWSYS_INSTALL_INCLUDE_DIR "${KWSYS_HEADER_INSTALL_DIR}") -ENDIF() -IF(NOT KWSYS_INSTALL_LIB_DIR) - STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_LIB_DIR +endif() +if(NOT KWSYS_INSTALL_LIB_DIR) + string(REGEX REPLACE "^/" "" KWSYS_INSTALL_LIB_DIR "${KWSYS_LIBRARY_INSTALL_DIR}") -ENDIF() -IF(NOT KWSYS_INSTALL_BIN_DIR) - STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_BIN_DIR +endif() +if(NOT KWSYS_INSTALL_BIN_DIR) + string(REGEX REPLACE "^/" "" KWSYS_INSTALL_BIN_DIR "${KWSYS_LIBRARY_INSTALL_DIR}") -ENDIF() +endif() # Setup header install rules. -SET(KWSYS_INSTALL_INCLUDE_OPTIONS) -IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) - SET(KWSYS_INSTALL_INCLUDE_OPTIONS ${KWSYS_INSTALL_INCLUDE_OPTIONS} +set(KWSYS_INSTALL_INCLUDE_OPTIONS) +if(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) + set(KWSYS_INSTALL_INCLUDE_OPTIONS ${KWSYS_INSTALL_INCLUDE_OPTIONS} COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT} ) -ENDIF() +endif() # Setup library install rules. -SET(KWSYS_INSTALL_LIBRARY_RULE) -SET(KWSYS_INSTALL_NAMELINK_RULE) -IF(KWSYS_INSTALL_LIB_DIR) - IF(KWSYS_INSTALL_EXPORT_NAME) - LIST(APPEND KWSYS_INSTALL_LIBRARY_RULE EXPORT ${KWSYS_INSTALL_EXPORT_NAME}) - ENDIF() +set(KWSYS_INSTALL_LIBRARY_RULE) +set(KWSYS_INSTALL_NAMELINK_RULE) +if(KWSYS_INSTALL_LIB_DIR) + if(KWSYS_INSTALL_EXPORT_NAME) + list(APPEND KWSYS_INSTALL_LIBRARY_RULE EXPORT ${KWSYS_INSTALL_EXPORT_NAME}) + endif() # Install the shared library to the lib directory. - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} NAMELINK_SKIP ) # Assign the shared library to the runtime component. - IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + if(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) + set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME} ) - ENDIF() - IF(KWSYS_BUILD_SHARED) - SET(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE} + endif() + if(KWSYS_BUILD_SHARED) + set(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE} LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} NAMELINK_ONLY ) # Assign the namelink to the development component. - IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) - SET(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE} + if(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) + set(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE} COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT} ) - ENDIF() - ENDIF() + endif() + endif() # Install the archive to the lib directory. - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} ARCHIVE DESTINATION ${KWSYS_INSTALL_LIB_DIR} ) # Assign the archive to the development component. - IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + if(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) + set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT} ) - ENDIF() -ENDIF() -IF(KWSYS_INSTALL_BIN_DIR) + endif() +endif() +if(KWSYS_INSTALL_BIN_DIR) # Install the runtime library to the bin directory. - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} RUNTIME DESTINATION ${KWSYS_INSTALL_BIN_DIR} ) # Assign the runtime library to the runtime component. - IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + if(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) + set(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME} ) - ENDIF() -ENDIF() + endif() +endif() # Do not support old KWSYS_*a_INSTALL_DIR variable names. -SET(KWSYS_HEADER_INSTALL_DIR) -SET(KWSYS_LIBRARY_INSTALL_DIR) +set(KWSYS_HEADER_INSTALL_DIR) +set(KWSYS_LIBRARY_INSTALL_DIR) # Generated source files will need this header. -STRING(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}" +string(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}" KWSYS_IN_SOURCE_BUILD) -IF(NOT KWSYS_IN_SOURCE_BUILD) - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/kwsysPrivate.h +if(NOT KWSYS_IN_SOURCE_BUILD) + configure_file(${PROJECT_SOURCE_DIR}/kwsysPrivate.h ${PROJECT_BINARY_DIR}/kwsysPrivate.h COPYONLY IMMEDIATE) -ENDIF() +endif() # Select plugin module file name convention. -IF(NOT KWSYS_DynamicLoader_PREFIX) - SET(KWSYS_DynamicLoader_PREFIX ${CMAKE_SHARED_MODULE_PREFIX}) -ENDIF() -IF(NOT KWSYS_DynamicLoader_SUFFIX) - SET(KWSYS_DynamicLoader_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX}) -ENDIF() +if(NOT KWSYS_DynamicLoader_PREFIX) + set(KWSYS_DynamicLoader_PREFIX ${CMAKE_SHARED_MODULE_PREFIX}) +endif() +if(NOT KWSYS_DynamicLoader_SUFFIX) + set(KWSYS_DynamicLoader_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX}) +endif() #----------------------------------------------------------------------------- # We require ANSI support from the C compiler. Add any needed flags. -IF(CMAKE_ANSI_CFLAGS) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}") -ENDIF() +if(CMAKE_ANSI_CFLAGS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}") +endif() #----------------------------------------------------------------------------- # Adjust compiler flags for some platforms. -IF(NOT CMAKE_COMPILER_IS_GNUCXX) - IF(CMAKE_SYSTEM MATCHES "OSF1-V.*") - STRING(REGEX MATCH "-timplicit_local" +if(NOT CMAKE_COMPILER_IS_GNUCXX) + if(CMAKE_SYSTEM MATCHES "OSF1-V.*") + string(REGEX MATCH "-timplicit_local" KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL "${CMAKE_CXX_FLAGS}") - STRING(REGEX MATCH "-no_implicit_include" + string(REGEX MATCH "-no_implicit_include" KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE "${CMAKE_CXX_FLAGS}") - IF(NOT KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local") - ENDIF() - IF(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no_implicit_include") - ENDIF() - ENDIF() - IF(CMAKE_SYSTEM MATCHES "HP-UX") - SET(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p") - IF(CMAKE_CXX_COMPILER_ID MATCHES "HP") + if(NOT KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local") + endif() + if(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no_implicit_include") + endif() + endif() + if(CMAKE_SYSTEM MATCHES "HP-UX") + set(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p") + if(CMAKE_CXX_COMPILER_ID MATCHES "HP") # it is known that version 3.85 fails and 6.25 works without these flags - IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4) + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4) # use new C++ library and improved template support - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98") - ENDIF() - ENDIF() - ENDIF() -ENDIF() -IF(KWSYS_STANDALONE) - IF(CMAKE_CXX_COMPILER_ID STREQUAL SunPro) - IF(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03") - ELSE() - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4") - ENDIF() - ENDIF() -ENDIF() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98") + endif() + endif() + endif() +endif() +if(KWSYS_STANDALONE) + if(CMAKE_CXX_COMPILER_ID STREQUAL SunPro) + if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4") + endif() + endif() +endif() #----------------------------------------------------------------------------- # Configure the standard library header wrappers based on compiler's @@ -365,75 +365,75 @@ KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_LONG_LONG "Checking whether C++ compiler has 'long long'" DIRECT) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS___INT64 "Checking whether C++ compiler has '__int64'" DIRECT) -IF(KWSYS_CXX_HAS___INT64) +if(KWSYS_CXX_HAS___INT64) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_AND___INT64 "Checking whether long and __int64 are the same type" DIRECT) - IF(KWSYS_CXX_HAS_LONG_LONG) + if(KWSYS_CXX_HAS_LONG_LONG) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_LONG_AND___INT64 "Checking whether long long and __int64 are the same type" DIRECT) - ENDIF() -ENDIF() + endif() +endif() # Enable the "long long" type if it is available. It is standard in # C99 and C++03 but not in earlier standards. -IF(KWSYS_CXX_HAS_LONG_LONG) - SET(KWSYS_USE_LONG_LONG 1) -ELSE() - SET(KWSYS_USE_LONG_LONG 0) -ENDIF() +if(KWSYS_CXX_HAS_LONG_LONG) + set(KWSYS_USE_LONG_LONG 1) +else() + set(KWSYS_USE_LONG_LONG 0) +endif() # Enable the "__int64" type if it is available and unique. It is not # standard. -SET(KWSYS_USE___INT64 0) -IF(KWSYS_CXX_HAS___INT64) - IF(NOT KWSYS_CXX_SAME_LONG_AND___INT64) - IF(NOT KWSYS_CXX_SAME_LONG_LONG_AND___INT64) - SET(KWSYS_USE___INT64 1) - ENDIF() - ENDIF() -ENDIF() - -IF(KWSYS_USE_Encoding) +set(KWSYS_USE___INT64 0) +if(KWSYS_CXX_HAS___INT64) + if(NOT KWSYS_CXX_SAME_LONG_AND___INT64) + if(NOT KWSYS_CXX_SAME_LONG_LONG_AND___INT64) + set(KWSYS_USE___INT64 1) + endif() + endif() +endif() + +if(KWSYS_USE_Encoding) # Look for type size helper macros. KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_WSTRING "Checking whether wstring is available" DIRECT) -ENDIF() +endif() -IF(KWSYS_USE_IOStream) +if(KWSYS_USE_IOStream) # Determine whether iostreams support long long. - IF(KWSYS_CXX_HAS_LONG_LONG) + if(KWSYS_CXX_HAS_LONG_LONG) KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM_LONG_LONG "Checking if istream supports long long" DIRECT) KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM_LONG_LONG "Checking if ostream supports long long" DIRECT) - ELSE() - SET(KWSYS_IOS_HAS_ISTREAM_LONG_LONG 0) - SET(KWSYS_IOS_HAS_OSTREAM_LONG_LONG 0) - ENDIF() - IF(KWSYS_CXX_HAS___INT64) + else() + set(KWSYS_IOS_HAS_ISTREAM_LONG_LONG 0) + set(KWSYS_IOS_HAS_OSTREAM_LONG_LONG 0) + endif() + if(KWSYS_CXX_HAS___INT64) KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM___INT64 "Checking if istream supports __int64" DIRECT) KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM___INT64 "Checking if ostream supports __int64" DIRECT) - ELSE() - SET(KWSYS_IOS_HAS_ISTREAM___INT64 0) - SET(KWSYS_IOS_HAS_OSTREAM___INT64 0) - ENDIF() -ENDIF() - -IF(KWSYS_NAMESPACE MATCHES "^kwsys$") - SET(KWSYS_NAME_IS_KWSYS 1) -ELSE() - SET(KWSYS_NAME_IS_KWSYS 0) -ENDIF() - -IF(KWSYS_BUILD_SHARED) - SET(KWSYS_BUILD_SHARED 1) - SET(KWSYS_LIBRARY_TYPE SHARED) -ELSE() - SET(KWSYS_BUILD_SHARED 0) - SET(KWSYS_LIBRARY_TYPE STATIC) -ENDIF() + else() + set(KWSYS_IOS_HAS_ISTREAM___INT64 0) + set(KWSYS_IOS_HAS_OSTREAM___INT64 0) + endif() +endif() + +if(KWSYS_NAMESPACE MATCHES "^kwsys$") + set(KWSYS_NAME_IS_KWSYS 1) +else() + set(KWSYS_NAME_IS_KWSYS 0) +endif() + +if(KWSYS_BUILD_SHARED) + set(KWSYS_BUILD_SHARED 1) + set(KWSYS_LIBRARY_TYPE SHARED) +else() + set(KWSYS_BUILD_SHARED 0) + set(KWSYS_LIBRARY_TYPE STATIC) +endif() if(NOT DEFINED KWSYS_BUILD_PIC) set(KWSYS_BUILD_PIC 0) @@ -446,32 +446,32 @@ KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_PTRDIFF_T "Checking whether C compiler has ptrdiff_t in stddef.h" DIRECT) KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_SSIZE_T "Checking whether C compiler has ssize_t in unistd.h" DIRECT) -IF(KWSYS_USE_Process) +if(KWSYS_USE_Process) KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC "Checking whether C compiler has clock_gettime" DIRECT) -ENDIF() +endif() -SET_SOURCE_FILES_PROPERTIES(ProcessUNIX.c System.c PROPERTIES +set_source_files_properties(ProcessUNIX.c System.c PROPERTIES COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T} -DKWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC=${KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC}" ) -IF(DEFINED KWSYS_PROCESS_USE_SELECT) - GET_PROPERTY(ProcessUNIX_FLAGS SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS) - SET_PROPERTY(SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS "${ProcessUNIX_FLAGS} -DKWSYSPE_USE_SELECT=${KWSYSPE_USE_SELECT}") -ENDIF() - -IF(KWSYS_USE_DynamicLoader) - GET_PROPERTY(KWSYS_SUPPORTS_SHARED_LIBS GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) - IF(KWSYS_SUPPORTS_SHARED_LIBS) - SET(KWSYS_SUPPORTS_SHARED_LIBS 1) - ELSE() - SET(KWSYS_SUPPORTS_SHARED_LIBS 0) - ENDIF() - SET_PROPERTY(SOURCE DynamicLoader.cxx APPEND PROPERTY COMPILE_DEFINITIONS +if(DEFINED KWSYS_PROCESS_USE_SELECT) + get_property(ProcessUNIX_FLAGS SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS) + set_property(SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS "${ProcessUNIX_FLAGS} -DKWSYSPE_USE_SELECT=${KWSYSPE_USE_SELECT}") +endif() + +if(KWSYS_USE_DynamicLoader) + get_property(KWSYS_SUPPORTS_SHARED_LIBS GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) + if(KWSYS_SUPPORTS_SHARED_LIBS) + set(KWSYS_SUPPORTS_SHARED_LIBS 1) + else() + set(KWSYS_SUPPORTS_SHARED_LIBS 0) + endif() + set_property(SOURCE DynamicLoader.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_SUPPORTS_SHARED_LIBS=${KWSYS_SUPPORTS_SHARED_LIBS}) -ENDIF() +endif() -IF(KWSYS_USE_SystemTools) +if(KWSYS_USE_SystemTools) if (NOT DEFINED KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP) set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1) endif () @@ -494,7 +494,7 @@ IF(KWSYS_USE_SystemTools) "Checking whether CXX compiler struct stat has st_mtim member" DIRECT) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIMESPEC "Checking whether CXX compiler struct stat has st_mtimespec member" DIRECT) - SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS + set_property(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV} KWSYS_CXX_HAS_UNSETENV=${KWSYS_CXX_HAS_UNSETENV} KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=${KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H} @@ -503,623 +503,623 @@ IF(KWSYS_USE_SystemTools) KWSYS_CXX_STAT_HAS_ST_MTIM=${KWSYS_CXX_STAT_HAS_ST_MTIM} KWSYS_CXX_STAT_HAS_ST_MTIMESPEC=${KWSYS_CXX_STAT_HAS_ST_MTIMESPEC} ) - IF(NOT WIN32) - IF(KWSYS_STANDALONE) - OPTION(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES "If true, Windows paths will be supported on Unix as well" ON) - ENDIF() - IF(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) - SET_PROPERTY(SOURCE SystemTools.cxx testSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS + if(NOT WIN32) + if(KWSYS_STANDALONE) + option(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES "If true, Windows paths will be supported on Unix as well" ON) + endif() + if(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) + set_property(SOURCE SystemTools.cxx testSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES ) - ENDIF() - ENDIF() + endif() + endif() # Disable getpwnam for static linux builds since it depends on shared glibc - GET_PROPERTY(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) - IF(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT SHARED_LIBS_SUPPORTED) - SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS + get_property(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) + if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT SHARED_LIBS_SUPPORTED) + set_property(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS HAVE_GETPWNAM=0 ) - ENDIF() -ENDIF() + endif() +endif() -IF(KWSYS_USE_SystemInformation) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY +if(KWSYS_USE_SystemInformation) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS SIZEOF_VOID_P=${CMAKE_SIZEOF_VOID_P}) - IF(NOT CYGWIN) - INCLUDE(CheckIncludeFiles) + if(NOT CYGWIN) + include(CheckIncludeFiles) CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" KWSYS_SYS_HAS_IFADDRS_H) - IF(KWSYS_SYS_HAS_IFADDRS_H) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + if(KWSYS_SYS_HAS_IFADDRS_H) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_SYS_HAS_IFADDRS_H=1) - ENDIF() - ENDIF() - IF(WIN32) - INCLUDE(CheckSymbolExists) - SET(CMAKE_REQUIRED_LIBRARIES Psapi) + endif() + endif() + if(WIN32) + include(CheckSymbolExists) + set(CMAKE_REQUIRED_LIBRARIES psapi) CHECK_SYMBOL_EXISTS(GetProcessMemoryInfo "windows.h;psapi.h" KWSYS_SYS_HAS_PSAPI) - UNSET(CMAKE_REQUIRED_LIBRARIES) - IF(KWSYS_SYS_HAS_PSAPI) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + unset(CMAKE_REQUIRED_LIBRARIES) + if(KWSYS_SYS_HAS_PSAPI) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_SYS_HAS_PSAPI=1) - IF(MSVC70 OR MSVC71) + if(MSVC70 OR MSVC71) # Suppress LNK4089: all references to 'PSAPI.DLL' discarded by /OPT:REF - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4089") - ENDIF() - ENDIF() - ENDIF() - IF(CMAKE_SYSTEM MATCHES "HP-UX") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4089") + endif() + endif() + endif() + if(CMAKE_SYSTEM MATCHES "HP-UX") CHECK_INCLUDE_FILES("sys/mpctl.h" KWSYS_SYS_HAS_MPCTL_H) - IF(KWSYS_SYS_HAS_MPCTL_H) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + if(KWSYS_SYS_HAS_MPCTL_H) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_SYS_HAS_MPCTL_H=1) - ENDIF() - ENDIF() - IF(CMAKE_SYSTEM MATCHES "BSD") + endif() + endif() + if(CMAKE_SYSTEM MATCHES "BSD") CHECK_INCLUDE_FILES("machine/cpu.h" KWSYS_SYS_HAS_MACHINE_CPU_H) - IF(KWSYS_SYS_HAS_MACHINE_CPU_H) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + if(KWSYS_SYS_HAS_MACHINE_CPU_H) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_SYS_HAS_MACHINE_CPU_H=1) - ENDIF() - ENDIF() + endif() + endif() KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64 "Checking whether CXX compiler has rlimit64" DIRECT) - SET(KWSYS_PLATFORM_CXX_TEST_DEFINES) - IF(KWSYS_CXX_HAS_RLIMIT64) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + set(KWSYS_PLATFORM_CXX_TEST_DEFINES) + if(KWSYS_CXX_HAS_RLIMIT64) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_CXX_HAS_RLIMIT64=1) - ENDIF() + endif() KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOL "Checking whether CXX compiler has atol" DIRECT) - IF(KWSYS_CXX_HAS_ATOL) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + if(KWSYS_CXX_HAS_ATOL) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOL=1) - ENDIF() + endif() KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOLL "Checking whether CXX compiler has atoll" DIRECT) - IF(KWSYS_CXX_HAS_ATOLL) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + if(KWSYS_CXX_HAS_ATOLL) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOLL=1) - ENDIF() + endif() KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS__ATOI64 "Checking whether CXX compiler has _atoi64" DIRECT) - IF(KWSYS_CXX_HAS__ATOI64) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + if(KWSYS_CXX_HAS__ATOI64) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_CXX_HAS__ATOI64=1) - ENDIF() - IF(UNIX) - INCLUDE(CheckIncludeFileCXX) + endif() + if(UNIX) + include(CheckIncludeFileCXX) # check for simple stack trace # usually it's in libc but on FreeBSD # it's in libexecinfo - FIND_LIBRARY(EXECINFO_LIB "execinfo") - MARK_AS_ADVANCED(EXECINFO_LIB) - IF (NOT EXECINFO_LIB) - SET(EXECINFO_LIB "") - ENDIF() + find_library(EXECINFO_LIB "execinfo") + mark_as_advanced(EXECINFO_LIB) + if (NOT EXECINFO_LIB) + set(EXECINFO_LIB "") + endif() CHECK_INCLUDE_FILE_CXX("execinfo.h" KWSYS_CXX_HAS_EXECINFOH) - IF (KWSYS_CXX_HAS_EXECINFOH) + if (KWSYS_CXX_HAS_EXECINFOH) # we have the backtrace header check if it # can be used with this compiler - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB}) + set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB}) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BACKTRACE "Checking whether backtrace works with this C++ compiler" DIRECT) - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) - IF (KWSYS_CXX_HAS_BACKTRACE) + set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) + if (KWSYS_CXX_HAS_BACKTRACE) # backtrace is supported by this system and compiler. # now check for the more advanced capabilities. - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE=1) # check for symbol lookup using dladdr CHECK_INCLUDE_FILE_CXX("dlfcn.h" KWSYS_CXX_HAS_DLFCNH) - IF (KWSYS_CXX_HAS_DLFCNH) + if (KWSYS_CXX_HAS_DLFCNH) # we have symbol lookup libraries and headers # check if they can be used with this compiler - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${CMAKE_DL_LIBS}) + set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${CMAKE_DL_LIBS}) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_DLADDR "Checking whether dladdr works with this C++ compiler" DIRECT) - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) - IF (KWSYS_CXX_HAS_DLADDR) + set(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) + if (KWSYS_CXX_HAS_DLADDR) # symbol lookup is supported by this system # and compiler. - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP=1) - ENDIF() - ENDIF() + endif() + endif() # c++ demangling support # check for cxxabi headers CHECK_INCLUDE_FILE_CXX("cxxabi.h" KWSYS_CXX_HAS_CXXABIH) - IF (KWSYS_CXX_HAS_CXXABIH) + if (KWSYS_CXX_HAS_CXXABIH) # check if cxxabi can be used with this # system and compiler. KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CXXABI "Checking whether cxxabi works with this C++ compiler" DIRECT) - IF (KWSYS_CXX_HAS_CXXABI) + if (KWSYS_CXX_HAS_CXXABI) # c++ demangle using cxxabi is supported with # this system and compiler - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE=1) - ENDIF() - ENDIF() + endif() + endif() # basic backtrace works better with release build # don't bother with advanced features for release - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1) - ENDIF() - ENDIF() - ENDIF() - IF(BORLAND) + endif() + endif() + endif() + if(BORLAND) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM "Checking whether Borland CXX compiler supports assembler instructions" DIRECT) - IF(KWSYS_CXX_HAS_BORLAND_ASM) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + if(KWSYS_CXX_HAS_BORLAND_ASM) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM=1) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM_CPUID "Checking whether Borland CXX compiler supports CPUID assembler instruction" DIRECT) - IF(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + if(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM_CPUID=1) - ENDIF() - ENDIF() - ENDIF() - IF(KWSYS_USE___INT64) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + endif() + endif() + endif() + if(KWSYS_USE___INT64) + set_property(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_USE___INT64=1) - ENDIF() - IF(KWSYS_USE_LONG_LONG) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + endif() + if(KWSYS_USE_LONG_LONG) + set_property(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_USE_LONG_LONG=1) - ENDIF() - IF(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + endif() + if(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) + set_property(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM_LONG_LONG=1) - ENDIF() - IF(KWSYS_IOS_HAS_OSTREAM___INT64) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + endif() + if(KWSYS_IOS_HAS_OSTREAM___INT64) + set_property(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM___INT64=1) - ENDIF() - IF(KWSYS_BUILD_SHARED) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + endif() + if(KWSYS_BUILD_SHARED) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_BUILD_SHARED=1) - ENDIF() + endif() - IF(UNIX AND NOT CYGWIN) + if(UNIX AND NOT CYGWIN) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_GETLOADAVG "Checking whether CXX compiler has getloadavg" DIRECT) - IF(KWSYS_CXX_HAS_GETLOADAVG) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + if(KWSYS_CXX_HAS_GETLOADAVG) + set_property(SOURCE SystemInformation.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_CXX_HAS_GETLOADAVG=1) - ENDIF() - ENDIF() -ENDIF() + endif() + endif() +endif() -IF(KWSYS_USE_FStream) +if(KWSYS_USE_FStream) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H "Checking whether <ext/stdio_filebuf.h> is available" DIRECT) -ENDIF() +endif() #----------------------------------------------------------------------------- # Choose a directory for the generated headers. -IF(NOT KWSYS_HEADER_ROOT) - SET(KWSYS_HEADER_ROOT "${PROJECT_BINARY_DIR}") -ENDIF() -SET(KWSYS_HEADER_DIR "${KWSYS_HEADER_ROOT}/${KWSYS_NAMESPACE}") -INCLUDE_DIRECTORIES(${KWSYS_HEADER_ROOT}) +if(NOT KWSYS_HEADER_ROOT) + set(KWSYS_HEADER_ROOT "${PROJECT_BINARY_DIR}") +endif() +set(KWSYS_HEADER_DIR "${KWSYS_HEADER_ROOT}/${KWSYS_NAMESPACE}") +include_directories(${KWSYS_HEADER_ROOT}) #----------------------------------------------------------------------------- -IF(KWSYS_INSTALL_DOC_DIR) +if(KWSYS_INSTALL_DOC_DIR) # Assign the license to the runtime component since it must be # distributed with binary forms of this software. - IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) - SET(KWSYS_INSTALL_LICENSE_OPTIONS ${KWSYS_INSTALL_LICENSE_OPTIONS} + if(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) + set(KWSYS_INSTALL_LICENSE_OPTIONS ${KWSYS_INSTALL_LICENSE_OPTIONS} COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME} ) - ENDIF() + endif() # Install the license under the documentation directory. - INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt DESTINATION ${KWSYS_INSTALL_DOC_DIR}/${KWSYS_NAMESPACE} ${KWSYS_INSTALL_LICENSE_OPTIONS}) -ENDIF() +endif() #----------------------------------------------------------------------------- # Build a list of classes and headers we need to implement the # selected components. Initialize with required components. -SET(KWSYS_CLASSES) -SET(KWSYS_H_FILES Configure SharedForward) -SET(KWSYS_HXX_FILES Configure String) +set(KWSYS_CLASSES) +set(KWSYS_H_FILES Configure SharedForward) +set(KWSYS_HXX_FILES Configure String) -IF(NOT CMake_SOURCE_DIR) - SET(KWSYS_HXX_FILES ${KWSYS_HXX_FILES} +if(NOT CMake_SOURCE_DIR) + set(KWSYS_HXX_FILES ${KWSYS_HXX_FILES} hashtable hash_fun hash_map hash_set ) -ENDIF() +endif() # Add selected C++ classes. -SET(cppclasses +set(cppclasses Directory DynamicLoader Encoding Glob RegularExpression SystemTools CommandLineArguments IOStream FStream SystemInformation ConsoleBuf ) -FOREACH(cpp ${cppclasses}) - IF(KWSYS_USE_${cpp}) +foreach(cpp ${cppclasses}) + if(KWSYS_USE_${cpp}) # Use the corresponding class. - SET(KWSYS_CLASSES ${KWSYS_CLASSES} ${cpp}) + set(KWSYS_CLASSES ${KWSYS_CLASSES} ${cpp}) # Load component-specific CMake code. - IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake) - INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake) - ENDIF() - ENDIF() -ENDFOREACH() + if(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake) + include(${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake) + endif() + endif() +endforeach() # Add selected C components. -FOREACH(c +foreach(c Process Base64 Encoding MD5 Terminal System String ) - IF(KWSYS_USE_${c}) + if(KWSYS_USE_${c}) # Use the corresponding header file. - SET(KWSYS_H_FILES ${KWSYS_H_FILES} ${c}) + set(KWSYS_H_FILES ${KWSYS_H_FILES} ${c}) # Load component-specific CMake code. - IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${c}.cmake) - INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${c}.cmake) - ENDIF() - ENDIF() -ENDFOREACH() + if(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${c}.cmake) + include(${PROJECT_SOURCE_DIR}/kwsys${c}.cmake) + endif() + endif() +endforeach() #----------------------------------------------------------------------------- # Build a list of sources for the library based on components that are # included. -SET(KWSYS_C_SRCS) -SET(KWSYS_CXX_SRCS) +set(KWSYS_C_SRCS) +set(KWSYS_CXX_SRCS) # Add the proper sources for this platform's Process implementation. -IF(KWSYS_USE_Process) - IF(NOT UNIX) +if(KWSYS_USE_Process) + if(NOT UNIX) # Use the Windows implementation. - SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c) - ELSE() + set(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c) + else() # Use the UNIX implementation. - SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c) - ENDIF() -ENDIF() + set(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c) + endif() +endif() # Add selected C sources. -FOREACH(c Base64 Encoding MD5 Terminal System String) - IF(KWSYS_USE_${c}) - IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}C.c) - LIST(APPEND KWSYS_C_SRCS ${c}C.c) - ELSE() - LIST(APPEND KWSYS_C_SRCS ${c}.c) - ENDIF() - ENDIF() -ENDFOREACH() +foreach(c Base64 Encoding MD5 Terminal System String) + if(KWSYS_USE_${c}) + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}C.c) + list(APPEND KWSYS_C_SRCS ${c}C.c) + else() + list(APPEND KWSYS_C_SRCS ${c}.c) + endif() + endif() +endforeach() # Configure headers of C++ classes and construct the list of sources. -FOREACH(c ${KWSYS_CLASSES}) +foreach(c ${KWSYS_CLASSES}) # Add this source to the list of source files for the library. - IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}CXX.cxx) - LIST(APPEND KWSYS_CXX_SRCS ${c}CXX.cxx) - ELSEIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}.cxx) - LIST(APPEND KWSYS_CXX_SRCS ${c}.cxx) - ENDIF() + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}CXX.cxx) + list(APPEND KWSYS_CXX_SRCS ${c}CXX.cxx) + elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}.cxx) + list(APPEND KWSYS_CXX_SRCS ${c}.cxx) + endif() # Configure the header for this class. - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${c}.hxx.in ${KWSYS_HEADER_DIR}/${c}.hxx + configure_file(${PROJECT_SOURCE_DIR}/${c}.hxx.in ${KWSYS_HEADER_DIR}/${c}.hxx @ONLY IMMEDIATE) - SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${c}.hxx) + set(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${c}.hxx) # Create an install target for the header. - IF(KWSYS_INSTALL_INCLUDE_DIR) - INSTALL(FILES ${KWSYS_HEADER_DIR}/${c}.hxx + if(KWSYS_INSTALL_INCLUDE_DIR) + install(FILES ${KWSYS_HEADER_DIR}/${c}.hxx DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE} ${KWSYS_INSTALL_INCLUDE_OPTIONS}) - ENDIF() -ENDFOREACH() + endif() +endforeach() # Configure C headers. -FOREACH(h ${KWSYS_H_FILES}) +foreach(h ${KWSYS_H_FILES}) # Configure the header into the given directory. - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.h.in ${KWSYS_HEADER_DIR}/${h}.h + configure_file(${PROJECT_SOURCE_DIR}/${h}.h.in ${KWSYS_HEADER_DIR}/${h}.h @ONLY IMMEDIATE) - SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ${KWSYS_HEADER_DIR}/${h}.h) + set(KWSYS_C_SRCS ${KWSYS_C_SRCS} ${KWSYS_HEADER_DIR}/${h}.h) # Create an install target for the header. - IF(KWSYS_INSTALL_INCLUDE_DIR) - INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.h + if(KWSYS_INSTALL_INCLUDE_DIR) + install(FILES ${KWSYS_HEADER_DIR}/${h}.h DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE} ${KWSYS_INSTALL_INCLUDE_OPTIONS}) - ENDIF() -ENDFOREACH() + endif() +endforeach() # Configure other C++ headers. -FOREACH(h ${KWSYS_HXX_FILES}) +foreach(h ${KWSYS_HXX_FILES}) # Configure the header into the given directory. - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.hxx.in ${KWSYS_HEADER_DIR}/${h}.hxx + configure_file(${PROJECT_SOURCE_DIR}/${h}.hxx.in ${KWSYS_HEADER_DIR}/${h}.hxx @ONLY IMMEDIATE) - SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${h}.hxx) + set(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${h}.hxx) # Create an install target for the header. - IF(KWSYS_INSTALL_INCLUDE_DIR) - INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.hxx + if(KWSYS_INSTALL_INCLUDE_DIR) + install(FILES ${KWSYS_HEADER_DIR}/${h}.hxx DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE} ${KWSYS_INSTALL_INCLUDE_OPTIONS}) - ENDIF() -ENDFOREACH() + endif() +endforeach() #----------------------------------------------------------------------------- # Add the library with the configured name and list of sources. -IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS) - IF(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE) - SET(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE}) - SET(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}_objects) - SET(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}_private) - SET(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_INTERFACE} ${KWSYS_TARGET_LINK}) - SET(KWSYS_LINK_DEPENDENCY INTERFACE) - ADD_LIBRARY(${KWSYS_TARGET_OBJECT} OBJECT +if(KWSYS_C_SRCS OR KWSYS_CXX_SRCS) + if(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE) + set(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE}) + set(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}_objects) + set(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}_private) + set(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_INTERFACE} ${KWSYS_TARGET_LINK}) + set(KWSYS_LINK_DEPENDENCY INTERFACE) + add_library(${KWSYS_TARGET_OBJECT} OBJECT ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS}) - IF(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC) - SET_PROPERTY(TARGET ${KWSYS_TARGET_OBJECT} PROPERTY + if(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC) + set_property(TARGET ${KWSYS_TARGET_OBJECT} PROPERTY POSITION_INDEPENDENT_CODE TRUE) - ENDIF() - ADD_LIBRARY(${KWSYS_TARGET_INTERFACE} INTERFACE) - ADD_LIBRARY(${KWSYS_TARGET_LINK} INTERFACE) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_LINK} INTERFACE + endif() + add_library(${KWSYS_TARGET_INTERFACE} INTERFACE) + add_library(${KWSYS_TARGET_LINK} INTERFACE) + target_link_libraries(${KWSYS_TARGET_LINK} INTERFACE ${KWSYS_TARGET_INTERFACE}) - TARGET_SOURCES(${KWSYS_TARGET_LINK} INTERFACE + target_sources(${KWSYS_TARGET_LINK} INTERFACE $<TARGET_OBJECTS:${KWSYS_TARGET_OBJECT}>) target_compile_features(${KWSYS_TARGET_OBJECT} PRIVATE ${KWSYS_CXX_COMPILE_FEATURES}) target_compile_features(${KWSYS_TARGET_INTERFACE} INTERFACE ${KWSYS_CXX_COMPILE_FEATURES}) - ELSE() - SET(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE}) - SET(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}) - SET(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}) + else() + set(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE}) + set(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}) + set(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}) set(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_LINK}) - SET(KWSYS_LINK_DEPENDENCY PUBLIC) - ADD_LIBRARY(${KWSYS_TARGET_INTERFACE} ${KWSYS_LIBRARY_TYPE} + set(KWSYS_LINK_DEPENDENCY PUBLIC) + add_library(${KWSYS_TARGET_INTERFACE} ${KWSYS_LIBRARY_TYPE} ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS}) target_compile_features(${KWSYS_TARGET_INTERFACE} PUBLIC ${KWSYS_CXX_COMPILE_FEATURES}) - ENDIF() + endif() if (KWSYS_ALIAS_TARGET) add_library(${KWSYS_ALIAS_TARGET} ALIAS ${KWSYS_TARGET_INTERFACE}) endif () - SET_TARGET_PROPERTIES(${KWSYS_TARGET_OBJECT} PROPERTIES + set_target_properties(${KWSYS_TARGET_OBJECT} PROPERTIES C_CLANG_TIDY "" CXX_CLANG_TIDY "" C_INCLUDE_WHAT_YOU_USE "" CXX_INCLUDE_WHAT_YOU_USE "" LABELS "${KWSYS_LABELS_LIB}") - IF(KWSYS_USE_DynamicLoader) - IF(UNIX) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} + if(KWSYS_USE_DynamicLoader) + if(UNIX) + target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ${CMAKE_DL_LIBS}) - ENDIF() - ENDIF() + endif() + endif() - IF(KWSYS_USE_SystemInformation) - IF(WIN32) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ws2_32) + if(KWSYS_USE_SystemInformation) + if(WIN32) + target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ws2_32) # link in dbghelp.dll for symbol lookup if MSVC 1800 or later # Note that the dbghelp runtime is part of MS Windows OS - IF(MSVC_VERSION AND NOT MSVC_VERSION VERSION_LESS 1800) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} dbghelp) - ENDIF() - IF(KWSYS_SYS_HAS_PSAPI) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} - Psapi) - ENDIF() - ELSEIF(UNIX) - IF (EXECINFO_LIB AND KWSYS_CXX_HAS_BACKTRACE) + if(MSVC_VERSION AND NOT MSVC_VERSION VERSION_LESS 1800) + target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} dbghelp) + endif() + if(KWSYS_SYS_HAS_PSAPI) + target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} + psapi) + endif() + elseif(UNIX) + if (EXECINFO_LIB AND KWSYS_CXX_HAS_BACKTRACE) # backtrace on FreeBSD is not in libc - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} + target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ${EXECINFO_LIB}) - ENDIF() - IF (KWSYS_CXX_HAS_DLADDR) + endif() + if (KWSYS_CXX_HAS_DLADDR) # for symbol lookup using dladdr - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} + target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ${CMAKE_DL_LIBS}) - ENDIF() - IF (CMAKE_SYSTEM_NAME STREQUAL "SunOS") - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} + endif() + if (CMAKE_SYSTEM_NAME STREQUAL "SunOS") + target_link_libraries(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} socket) - ENDIF() - ENDIF() - ENDIF() + endif() + endif() + endif() # Apply user-defined target properties to the library. - IF(KWSYS_PROPERTIES_CXX) - SET_TARGET_PROPERTIES(${KWSYS_TARGET_INTERFACE} PROPERTIES + if(KWSYS_PROPERTIES_CXX) + set_target_properties(${KWSYS_TARGET_INTERFACE} PROPERTIES ${KWSYS_PROPERTIES_CXX}) - ENDIF() + endif() # Set up include usage requirement - IF(COMMAND TARGET_INCLUDE_DIRECTORIES) - TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_INTERFACE} INTERFACE + if(COMMAND TARGET_INCLUDE_DIRECTORIES) + target_include_directories(${KWSYS_TARGET_INTERFACE} INTERFACE $<BUILD_INTERFACE:${KWSYS_HEADER_ROOT}>) - IF(KWSYS_INSTALL_INCLUDE_DIR) - TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_INTERFACE} INTERFACE + if(KWSYS_INSTALL_INCLUDE_DIR) + target_include_directories(${KWSYS_TARGET_INTERFACE} INTERFACE $<INSTALL_INTERFACE:${KWSYS_INSTALL_INCLUDE_DIR}>) - ENDIF() - ENDIF() + endif() + endif() # Create an install target for the library. - IF(KWSYS_INSTALL_LIBRARY_RULE) - INSTALL(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_LIBRARY_RULE}) - ENDIF() - IF(KWSYS_INSTALL_NAMELINK_RULE) - INSTALL(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_NAMELINK_RULE}) - ENDIF() -ENDIF() + if(KWSYS_INSTALL_LIBRARY_RULE) + install(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_LIBRARY_RULE}) + endif() + if(KWSYS_INSTALL_NAMELINK_RULE) + install(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_NAMELINK_RULE}) + endif() +endif() # Add a C-only library if requested. -IF(KWSYS_ENABLE_C AND KWSYS_C_SRCS) - IF(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE) - SET(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c) - SET(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c_objects) - SET(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c_private) - SET(KWSYS_TARGET_C_INSTALL +if(KWSYS_ENABLE_C AND KWSYS_C_SRCS) + if(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE) + set(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c) + set(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c_objects) + set(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c_private) + set(KWSYS_TARGET_C_INSTALL ${KWSYS_TARGET_C_INTERFACE} ${KWSYS_TARGET_C_LINK}) - SET(KWSYS_LINK_DEPENDENCY INTERFACE) - ADD_LIBRARY(${KWSYS_TARGET_C_OBJECT} OBJECT ${KWSYS_C_SRCS}) - IF(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC) - SET_PROPERTY(TARGET ${KWSYS_TARGET_C_OBJECT} PROPERTY + set(KWSYS_LINK_DEPENDENCY INTERFACE) + add_library(${KWSYS_TARGET_C_OBJECT} OBJECT ${KWSYS_C_SRCS}) + if(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC) + set_property(TARGET ${KWSYS_TARGET_C_OBJECT} PROPERTY POSITION_INDEPENDENT_CODE TRUE) - ENDIF() - ADD_LIBRARY(${KWSYS_TARGET_C_INTERFACE} INTERFACE) - ADD_LIBRARY(${KWSYS_TARGET_C_LINK} INTERFACE) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_C_LINK} INTERFACE + endif() + add_library(${KWSYS_TARGET_C_INTERFACE} INTERFACE) + add_library(${KWSYS_TARGET_C_LINK} INTERFACE) + target_link_libraries(${KWSYS_TARGET_C_LINK} INTERFACE ${KWSYS_TARGET_C_INTERFACE}) - TARGET_SOURCES(${KWSYS_TARGET_C_LINK} INTERFACE + target_sources(${KWSYS_TARGET_C_LINK} INTERFACE $<TARGET_OBJECTS:${KWSYS_TARGET_C_OBJECT}>) - ELSE() - SET(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c) - SET(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c) - SET(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c) - SET(KWSYS_TARGET_C_INSTALL ${KWSYS_TARGET_C_LINK}) - SET(KWSYS_LINK_DEPENDENCY PUBLIC) - ADD_LIBRARY(${KWSYS_TARGET_C_INTERFACE} ${KWSYS_LIBRARY_TYPE} + else() + set(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c) + set(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c) + set(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c) + set(KWSYS_TARGET_C_INSTALL ${KWSYS_TARGET_C_LINK}) + set(KWSYS_LINK_DEPENDENCY PUBLIC) + add_library(${KWSYS_TARGET_C_INTERFACE} ${KWSYS_LIBRARY_TYPE} ${KWSYS_C_SRCS}) - ENDIF() - SET_TARGET_PROPERTIES(${KWSYS_TARGET_C_OBJECT} PROPERTIES + endif() + set_target_properties(${KWSYS_TARGET_C_OBJECT} PROPERTIES LABELS "${KWSYS_LABELS_LIB}") # Apply user-defined target properties to the library. - IF(KWSYS_PROPERTIES_C) - SET_TARGET_PROPERTIES(${KWSYS_TARGET_C_INTERFACE} PROPERTIES + if(KWSYS_PROPERTIES_C) + set_target_properties(${KWSYS_TARGET_C_INTERFACE} PROPERTIES ${KWSYS_PROPERTIES_C}) - ENDIF() + endif() # Set up include usage requirement - IF(COMMAND TARGET_INCLUDE_DIRECTORIES) - TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_C_INTERFACE} INTERFACE + if(COMMAND TARGET_INCLUDE_DIRECTORIES) + target_include_directories(${KWSYS_TARGET_C_INTERFACE} INTERFACE $<BUILD_INTERFACE:${KWSYS_HEADER_ROOT}>) - IF(KWSYS_INSTALL_INCLUDE_DIR) - TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_C_INTERFACE} INTERFACE + if(KWSYS_INSTALL_INCLUDE_DIR) + target_include_directories(${KWSYS_TARGET_C_INTERFACE} INTERFACE $<INSTALL_INTERFACE:${KWSYS_INSTALL_INCLUDE_DIR}>) - ENDIF() - ENDIF() + endif() + endif() # Create an install target for the library. - IF(KWSYS_INSTALL_LIBRARY_RULE) - INSTALL(TARGETS ${KWSYS_TARGET_C_INSTALL}) - ENDIF() -ENDIF() + if(KWSYS_INSTALL_LIBRARY_RULE) + install(TARGETS ${KWSYS_TARGET_C_INSTALL}) + endif() +endif() # For building kwsys itself, we use a macro defined on the command # line to configure the namespace in the C and C++ source files. -ADD_DEFINITIONS("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}") +add_definitions("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}") # Disable deprecation warnings for standard C functions. -IF(MSVC OR (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "Intel" OR +if(MSVC OR (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "Intel" OR (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")))) - ADD_DEFINITIONS( + add_definitions( -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_DEPRECATE ) -ENDIF() +endif() -IF(WIN32) +if(WIN32) # Help enforce the use of wide Windows apis. - ADD_DEFINITIONS(-DUNICODE -D_UNICODE) -ENDIF() + add_definitions(-DUNICODE -D_UNICODE) +endif() -IF(KWSYS_USE_String) +if(KWSYS_USE_String) # Activate code in "String.c". See the comment in the source. - SET_SOURCE_FILES_PROPERTIES(String.c PROPERTIES + set_source_files_properties(String.c PROPERTIES COMPILE_FLAGS "-DKWSYS_STRING_C") -ENDIF() +endif() -IF(KWSYS_USE_Encoding) +if(KWSYS_USE_Encoding) # Set default 8 bit encoding in "EndcodingC.c". - SET_PROPERTY(SOURCE EncodingC.c EncodingCXX.cxx APPEND PROPERTY COMPILE_DEFINITIONS + set_property(SOURCE EncodingC.c EncodingCXX.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) -ENDIF() +endif() #----------------------------------------------------------------------------- # Setup testing if not being built as part of another project. -IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) - IF(BUILD_TESTING) +if(KWSYS_STANDALONE OR CMake_SOURCE_DIR) + if(BUILD_TESTING) # Compute the location of executables. - SET(EXEC_DIR "${CMAKE_CURRENT_BINARY_DIR}") - IF(EXECUTABLE_OUTPUT_PATH) - SET(EXEC_DIR "${EXECUTABLE_OUTPUT_PATH}") - ENDIF() + set(EXEC_DIR "${CMAKE_CURRENT_BINARY_DIR}") + if(CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(EXEC_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") + endif() # C tests - SET(KWSYS_C_TESTS + set(KWSYS_C_TESTS testEncode.c testTerminal.c ) - IF(KWSYS_STANDALONE) - SET(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail.c) - ENDIF() - CREATE_TEST_SOURCELIST( + if(KWSYS_STANDALONE) + set(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail.c) + endif() + create_test_sourcelist( KWSYS_C_TEST_SRCS ${KWSYS_NAMESPACE}TestsC.c ${KWSYS_C_TESTS} ) - ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsC ${KWSYS_C_TEST_SRCS}) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsC PROPERTY LABELS ${KWSYS_LABELS_EXE}) - TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsC ${KWSYS_TARGET_C_LINK}) - FOREACH(testfile ${KWSYS_C_TESTS}) + add_executable(${KWSYS_NAMESPACE}TestsC ${KWSYS_C_TEST_SRCS}) + set_property(TARGET ${KWSYS_NAMESPACE}TestsC PROPERTY LABELS ${KWSYS_LABELS_EXE}) + target_link_libraries(${KWSYS_NAMESPACE}TestsC ${KWSYS_TARGET_C_LINK}) + foreach(testfile ${KWSYS_C_TESTS}) get_filename_component(test "${testfile}" NAME_WE) - ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}}) - SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST}) - ENDFOREACH() + add_test(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}}) + set_property(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST}) + endforeach() # C++ tests - IF(NOT WATCOM AND NOT CMake_SOURCE_DIR) - SET(KWSYS_CXX_TESTS + if(NOT WATCOM AND NOT CMake_SOURCE_DIR) + set(KWSYS_CXX_TESTS testHashSTL.cxx ) - ENDIF() - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + endif() + set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testConfigure.cxx testSystemTools.cxx testCommandLineArguments.cxx testCommandLineArguments1.cxx testDirectory.cxx ) - IF(KWSYS_STL_HAS_WSTRING) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + if(KWSYS_STL_HAS_WSTRING) + set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testEncoding.cxx ) - ENDIF() - IF(KWSYS_USE_FStream) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + endif() + if(KWSYS_USE_FStream) + set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testFStream.cxx ) - ENDIF() - IF(KWSYS_USE_ConsoleBuf) - ADD_EXECUTABLE(testConsoleBufChild testConsoleBufChild.cxx) - SET_PROPERTY(TARGET testConsoleBufChild PROPERTY C_CLANG_TIDY "") - SET_PROPERTY(TARGET testConsoleBufChild PROPERTY CXX_CLANG_TIDY "") - SET_PROPERTY(TARGET testConsoleBufChild PROPERTY C_INCLUDE_WHAT_YOU_USE "") - SET_PROPERTY(TARGET testConsoleBufChild PROPERTY CXX_INCLUDE_WHAT_YOU_USE "") - SET_PROPERTY(TARGET testConsoleBufChild PROPERTY LABELS ${KWSYS_LABELS_EXE}) - TARGET_LINK_LIBRARIES(testConsoleBufChild ${KWSYS_TARGET_LINK}) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + endif() + if(KWSYS_USE_ConsoleBuf) + add_executable(testConsoleBufChild testConsoleBufChild.cxx) + set_property(TARGET testConsoleBufChild PROPERTY C_CLANG_TIDY "") + set_property(TARGET testConsoleBufChild PROPERTY CXX_CLANG_TIDY "") + set_property(TARGET testConsoleBufChild PROPERTY C_INCLUDE_WHAT_YOU_USE "") + set_property(TARGET testConsoleBufChild PROPERTY CXX_INCLUDE_WHAT_YOU_USE "") + set_property(TARGET testConsoleBufChild PROPERTY LABELS ${KWSYS_LABELS_EXE}) + target_link_libraries(testConsoleBufChild ${KWSYS_TARGET_LINK}) + set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testConsoleBuf.cxx ) - IF(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "19.0.23506") set_property(SOURCE testConsoleBuf.cxx testConsoleBufChild.cxx PROPERTY COMPILE_FLAGS /utf-8) - ENDIF() - SET_PROPERTY(SOURCE testConsoleBuf.cxx APPEND PROPERTY COMPILE_DEFINITIONS + endif() + set_property(SOURCE testConsoleBuf.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) - ENDIF() - IF(KWSYS_USE_SystemInformation) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation.cxx) - ENDIF() - IF(KWSYS_USE_DynamicLoader) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testDynamicLoader.cxx) + endif() + if(KWSYS_USE_SystemInformation) + set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation.cxx) + endif() + if(KWSYS_USE_DynamicLoader) + set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testDynamicLoader.cxx) # If kwsys contains the DynamicLoader, need extra library - ADD_LIBRARY(${KWSYS_NAMESPACE}TestDynload MODULE testDynload.c) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestDynload PROPERTY LABELS ${KWSYS_LABELS_LIB}) - ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestDynload ${KWSYS_TARGET_INTERFACE}) + add_library(${KWSYS_NAMESPACE}TestDynload MODULE testDynload.c) + set_property(TARGET ${KWSYS_NAMESPACE}TestDynload PROPERTY LABELS ${KWSYS_LABELS_LIB}) + add_dependencies(${KWSYS_NAMESPACE}TestDynload ${KWSYS_TARGET_INTERFACE}) if (WIN32) # Windows tests supported flags. @@ -1134,33 +1134,33 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) add_dependencies(${KWSYS_NAMESPACE}TestDynloadUse ${KWSYS_TARGET_INTERFACE}) target_link_libraries(${KWSYS_NAMESPACE}TestDynloadUse PRIVATE ${KWSYS_NAMESPACE}TestDynloadImpl) endif () - ENDIF() - CREATE_TEST_SOURCELIST( + endif() + create_test_sourcelist( KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx ${KWSYS_CXX_TESTS} ) - ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_CXX_TEST_SRCS}) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_CLANG_TIDY "") - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_CLANG_TIDY "") - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_INCLUDE_WHAT_YOU_USE "") - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_INCLUDE_WHAT_YOU_USE "") - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY LABELS ${KWSYS_LABELS_EXE}) - TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_TARGET_LINK}) - - SET(TEST_SYSTEMTOOLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - SET(TEST_SYSTEMTOOLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") - CONFIGURE_FILE( + add_executable(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_CXX_TEST_SRCS}) + set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_CLANG_TIDY "") + set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_CLANG_TIDY "") + set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_INCLUDE_WHAT_YOU_USE "") + set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_INCLUDE_WHAT_YOU_USE "") + set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY LABELS ${KWSYS_LABELS_EXE}) + target_link_libraries(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_TARGET_LINK}) + + set(TEST_SYSTEMTOOLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(TEST_SYSTEMTOOLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") + configure_file( ${PROJECT_SOURCE_DIR}/testSystemTools.h.in ${PROJECT_BINARY_DIR}/testSystemTools.h) - INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}) + include_directories(${PROJECT_BINARY_DIR}) - IF(CTEST_TEST_KWSYS) - CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/ExtraTest.cmake.in" + if(CTEST_TEST_KWSYS) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/ExtraTest.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake") - SET_DIRECTORY_PROPERTIES(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake") - ENDIF() + set_directory_properties(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake") + endif() - SET(KWSYS_TEST_ARGS_testCommandLineArguments + set(KWSYS_TEST_ARGS_testCommandLineArguments --another-bool-variable --long3=opt --set-bool-arg1 @@ -1179,7 +1179,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) -C=test --long2 hello ) - SET(KWSYS_TEST_ARGS_testCommandLineArguments1 + set(KWSYS_TEST_ARGS_testCommandLineArguments1 --ignored -n 24 --second-ignored @@ -1188,73 +1188,73 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) -p some junk at the end ) - FOREACH(testfile ${KWSYS_CXX_TESTS}) + foreach(testfile ${KWSYS_CXX_TESTS}) get_filename_component(test "${testfile}" NAME_WE) - ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}}) - SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST}) - ENDFOREACH() + add_test(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}}) + set_property(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST}) + endforeach() # Process tests. - ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestProcess testProcess.c) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestProcess PROPERTY LABELS ${KWSYS_LABELS_EXE}) - TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestProcess ${KWSYS_TARGET_C_LINK}) - IF(NOT CYGWIN) - SET(KWSYS_TEST_PROCESS_7 7) - ENDIF() - FOREACH(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10) - ADD_TEST(kwsys.testProcess-${n} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n}) - SET_PROPERTY(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST}) - SET_TESTS_PROPERTIES(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120) - ENDFOREACH() - - SET(testProcess_COMPILE_FLAGS "") + add_executable(${KWSYS_NAMESPACE}TestProcess testProcess.c) + set_property(TARGET ${KWSYS_NAMESPACE}TestProcess PROPERTY LABELS ${KWSYS_LABELS_EXE}) + target_link_libraries(${KWSYS_NAMESPACE}TestProcess ${KWSYS_TARGET_C_LINK}) + if(NOT CYGWIN) + set(KWSYS_TEST_PROCESS_7 7) + endif() + foreach(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10) + add_test(kwsys.testProcess-${n} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n}) + set_property(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST}) + set_tests_properties(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120) + endforeach() + + set(testProcess_COMPILE_FLAGS "") # Some Apple compilers produce bad optimizations in this source. - IF(APPLE AND CMAKE_C_COMPILER_ID MATCHES "^(GNU|LLVM)$") - SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -O0") - ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "XL") + if(APPLE AND CMAKE_C_COMPILER_ID MATCHES "^(GNU|LLVM)$") + set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -O0") + elseif(CMAKE_C_COMPILER_ID STREQUAL "XL") # Tell IBM XL not to warn about our test infinite loop - IF(CMAKE_SYSTEM MATCHES "Linux.*ppc64le" + if(CMAKE_SYSTEM MATCHES "Linux.*ppc64le" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "16.1.0" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS "13.1.1") # v13.1.[1-6] on Linux ppc64le is clang based and does not accept # the -qsuppress option, so just suppress all warnings. - SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -w") - ELSE() - SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -qsuppress=1500-010") - ENDIF() - ENDIF() - IF(CMAKE_C_FLAGS MATCHES "-fsanitize=") - SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -DCRASH_USING_ABORT") - ENDIF() - SET_PROPERTY(SOURCE testProcess.c PROPERTY COMPILE_FLAGS "${testProcess_COMPILE_FLAGS}") + set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -w") + else() + set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -qsuppress=1500-010") + endif() + endif() + if(CMAKE_C_FLAGS MATCHES "-fsanitize=") + set(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -DCRASH_USING_ABORT") + endif() + set_property(SOURCE testProcess.c PROPERTY COMPILE_FLAGS "${testProcess_COMPILE_FLAGS}") # Test SharedForward - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/testSharedForward.c.in + configure_file(${PROJECT_SOURCE_DIR}/testSharedForward.c.in ${PROJECT_BINARY_DIR}/testSharedForward.c @ONLY IMMEDIATE) - ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestSharedForward + add_executable(${KWSYS_NAMESPACE}TestSharedForward ${PROJECT_BINARY_DIR}/testSharedForward.c) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestSharedForward PROPERTY LABELS ${KWSYS_LABELS_EXE}) - ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestSharedForward ${KWSYS_TARGET_C_LINK}) - ADD_TEST(kwsys.testSharedForward ${EXEC_DIR}/${KWSYS_NAMESPACE}TestSharedForward 1) - SET_PROPERTY(TEST kwsys.testSharedForward PROPERTY LABELS ${KWSYS_LABELS_TEST}) + set_property(TARGET ${KWSYS_NAMESPACE}TestSharedForward PROPERTY LABELS ${KWSYS_LABELS_EXE}) + add_dependencies(${KWSYS_NAMESPACE}TestSharedForward ${KWSYS_TARGET_C_LINK}) + add_test(kwsys.testSharedForward ${EXEC_DIR}/${KWSYS_NAMESPACE}TestSharedForward 1) + set_property(TEST kwsys.testSharedForward PROPERTY LABELS ${KWSYS_LABELS_TEST}) # Configure some test properties. - IF(KWSYS_STANDALONE) + if(KWSYS_STANDALONE) # We expect test to fail - SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES WILL_FAIL ON) - GET_TEST_PROPERTY(kwsys.testFail WILL_FAIL wfv) - SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES MEASUREMENT "Some Key=Some Value") - MESSAGE(STATUS "GET_TEST_PROPERTY returned: ${wfv}") - ENDIF() + set_tests_properties(kwsys.testFail PROPERTIES WILL_FAIL ON) + get_test_property(kwsys.testFail WILL_FAIL wfv) + set_tests_properties(kwsys.testFail PROPERTIES MEASUREMENT "Some Key=Some Value") + message(STATUS "GET_TEST_PROPERTY returned: ${wfv}") + endif() # Set up ctest custom configuration file. - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/CTestCustom.cmake.in + configure_file(${PROJECT_SOURCE_DIR}/CTestCustom.cmake.in ${PROJECT_BINARY_DIR}/CTestCustom.cmake @ONLY) # Suppress known consistent failures on buggy systems. - IF(KWSYS_TEST_BOGUS_FAILURES) - SET_TESTS_PROPERTIES(${KWSYS_TEST_BOGUS_FAILURES} PROPERTIES WILL_FAIL ON) - ENDIF() + if(KWSYS_TEST_BOGUS_FAILURES) + set_tests_properties(${KWSYS_TEST_BOGUS_FAILURES} PROPERTIES WILL_FAIL ON) + endif() - ENDIF() -ENDIF() + endif() +endif() diff --git a/Source/kwsys/CTestCustom.cmake.in b/Source/kwsys/CTestCustom.cmake.in index 760221b..c07f0f3 100644 --- a/Source/kwsys/CTestCustom.cmake.in +++ b/Source/kwsys/CTestCustom.cmake.in @@ -12,3 +12,7 @@ list(APPEND CTEST_CUSTOM_MEMCHECK_IGNORE kwsys.testProcess-10 ) + +list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION + "LICENSE WARNING" + ) diff --git a/Source/kwsys/CommandLineArguments.cxx b/Source/kwsys/CommandLineArguments.cxx index 3fd1955..a2ed874 100644 --- a/Source/kwsys/CommandLineArguments.cxx +++ b/Source/kwsys/CommandLineArguments.cxx @@ -66,26 +66,21 @@ class CommandLineArgumentsMapOfStrucs class CommandLineArgumentsInternal { public: - CommandLineArgumentsInternal() - : UnknownArgumentCallback{ nullptr } - , ClientData{ nullptr } - , LastArgument{ 0 } - { - } + CommandLineArgumentsInternal() = default; - typedef CommandLineArgumentsVectorOfStrings VectorOfStrings; - typedef CommandLineArgumentsMapOfStrucs CallbacksMap; - typedef kwsys::String String; - typedef CommandLineArgumentsSetOfStrings SetOfStrings; + using VectorOfStrings = CommandLineArgumentsVectorOfStrings; + using CallbacksMap = CommandLineArgumentsMapOfStrucs; + using String = kwsys::String; + using SetOfStrings = CommandLineArgumentsSetOfStrings; VectorOfStrings Argv; String Argv0; CallbacksMap Callbacks; - CommandLineArguments::ErrorCallbackType UnknownArgumentCallback; - void* ClientData; + CommandLineArguments::ErrorCallbackType UnknownArgumentCallback{ nullptr }; + void* ClientData{ nullptr }; - VectorOfStrings::size_type LastArgument; + VectorOfStrings::size_type LastArgument{ 0 }; VectorOfStrings UnusedArguments; }; @@ -424,8 +419,7 @@ void CommandLineArguments::SetUnknownArgumentCallback( const char* CommandLineArguments::GetHelp(const char* arg) { - CommandLineArguments::Internal::CallbacksMap::iterator it = - this->Internals->Callbacks.find(arg); + auto it = this->Internals->Callbacks.find(arg); if (it == this->Internals->Callbacks.end()) { return nullptr; } @@ -434,8 +428,7 @@ const char* CommandLineArguments::GetHelp(const char* arg) // one point to if this one is pointing to another argument. CommandLineArgumentsCallbackStructure* cs = &(it->second); for (;;) { - CommandLineArguments::Internal::CallbacksMap::iterator hit = - this->Internals->Callbacks.find(cs->Help); + auto hit = this->Internals->Callbacks.find(cs->Help); if (hit == this->Internals->Callbacks.end()) { break; } @@ -470,9 +463,8 @@ void CommandLineArguments::GenerateHelp() // Collapse all arguments into the map of vectors of all arguments that do // the same thing. CommandLineArguments::Internal::CallbacksMap::iterator it; - typedef std::map<CommandLineArguments::Internal::String, - CommandLineArguments::Internal::SetOfStrings> - MapArgs; + using MapArgs = std::map<CommandLineArguments::Internal::String, + CommandLineArguments::Internal::SetOfStrings>; MapArgs mp; MapArgs::iterator mpit, smpit; for (it = this->Internals->Callbacks.begin(); @@ -709,7 +701,7 @@ bool CommandLineArguments::PopulateVariable( if (cs->Callback) { if (!cs->Callback(cs->Argument, value, cs->CallData)) { this->Internals->LastArgument--; - return 0; + return false; } } CommandLineArguments_DEBUG("Set argument: " << cs->Argument << " to " @@ -759,10 +751,10 @@ bool CommandLineArguments::PopulateVariable( std::cerr << "Got unknown variable type: \"" << cs->VariableType << "\"" << std::endl; this->Internals->LastArgument--; - return 0; + return false; } } - return 1; + return true; } } // namespace KWSYS_NAMESPACE diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx index e379182..1a772b4 100644 --- a/Source/kwsys/Directory.cxx +++ b/Source/kwsys/Directory.cxx @@ -204,15 +204,15 @@ bool Directory::Load(const std::string& name) DIR* dir = opendir(name.c_str()); if (!dir) { - return 0; + return false; } for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { - this->Internal->Files.push_back(d->d_name); + this->Internal->Files.emplace_back(d->d_name); } this->Internal->Path = name; closedir(dir); - return 1; + return true; } unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) diff --git a/Source/kwsys/Encoding.hxx.in b/Source/kwsys/Encoding.hxx.in index b067521..75a2d4d 100644 --- a/Source/kwsys/Encoding.hxx.in +++ b/Source/kwsys/Encoding.hxx.in @@ -68,6 +68,8 @@ public: * absolute paths with Windows-style backslashes. **/ static std::wstring ToWindowsExtendedPath(std::string const&); + static std::wstring ToWindowsExtendedPath(const char* source); + static std::wstring ToWindowsExtendedPath(std::wstring const& wsource); # endif #endif // @KWSYS_NAMESPACE@_STL_HAS_WSTRING diff --git a/Source/kwsys/EncodingCXX.cxx b/Source/kwsys/EncodingCXX.cxx index 4593c92..5cad934 100644 --- a/Source/kwsys/EncodingCXX.cxx +++ b/Source/kwsys/EncodingCXX.cxx @@ -221,8 +221,18 @@ std::string Encoding::ToNarrow(const wchar_t* wcstr) // Convert local paths to UNC style paths std::wstring Encoding::ToWindowsExtendedPath(std::string const& source) { - std::wstring wsource = Encoding::ToWide(source); + return ToWindowsExtendedPath(ToWide(source)); +} +// Convert local paths to UNC style paths +std::wstring Encoding::ToWindowsExtendedPath(const char* source) +{ + return ToWindowsExtendedPath(ToWide(source)); +} + +// Convert local paths to UNC style paths +std::wstring Encoding::ToWindowsExtendedPath(std::wstring const& wsource) +{ // Resolve any relative paths DWORD wfull_len; @@ -269,7 +279,7 @@ std::wstring Encoding::ToWindowsExtendedPath(std::string const& source) // If this case has been reached, then the path is invalid. Leave it // unchanged - return Encoding::ToWide(source); + return wsource; } # endif diff --git a/Source/kwsys/ExtraTest.cmake.in b/Source/kwsys/ExtraTest.cmake.in index e8c0a1c..4cec9e2 100644 --- a/Source/kwsys/ExtraTest.cmake.in +++ b/Source/kwsys/ExtraTest.cmake.in @@ -1 +1 @@ -MESSAGE("*** This message is generated by message inside a file that is included in DartTestfile.txt ***") +message("*** This message is generated by message inside a file that is included in DartTestfile.txt ***") diff --git a/Source/kwsys/FStream.hxx.in b/Source/kwsys/FStream.hxx.in index d79bbdf..b424488 100644 --- a/Source/kwsys/FStream.hxx.in +++ b/Source/kwsys/FStream.hxx.in @@ -87,7 +87,7 @@ public: bool _open(char const* file_name, std::ios_base::openmode mode) { - if (is_open() || file_) { + if (_is_open() || file_) { return false; } # if defined(_MSC_VER) @@ -108,7 +108,7 @@ public: return success; } - bool is_open() + bool _is_open() { if (!buf_) { return false; @@ -116,7 +116,7 @@ public: return buf_->is_open(); } - bool is_open() const + bool _is_open() const { if (!buf_) { return false; @@ -198,9 +198,11 @@ public: this->_set_state(this->_open(file_name, mode), this, this); } + bool is_open() { return this->_is_open(); } + void close() { this->_set_state(this->_close(), this, this); } - using basic_efilebuf<CharType, Traits>::is_open; + using basic_efilebuf<CharType, Traits>::_is_open; internal_buffer_type* rdbuf() const { return this->buf_; } @@ -212,7 +214,7 @@ class basic_ofstream : public std::basic_ostream<CharType, Traits> , public basic_efilebuf<CharType, Traits> { - using basic_efilebuf<CharType, Traits>::is_open; + using basic_efilebuf<CharType, Traits>::_is_open; public: typedef typename basic_efilebuf<CharType, Traits>::internal_buffer_type @@ -242,6 +244,8 @@ public: void close() { this->_set_state(this->_close(), this, this); } + bool is_open() { return this->_is_open(); } + internal_buffer_type* rdbuf() const { return this->buf_; } ~basic_ofstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); } diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx index 34bb0d0..658b816 100644 --- a/Source/kwsys/Glob.cxx +++ b/Source/kwsys/Glob.cxx @@ -415,8 +415,7 @@ bool Glob::FindFiles(const std::string& inexpr, GlobMessages* messages) void Glob::AddExpression(const std::string& expr) { - this->Internals->Expressions.push_back( - kwsys::RegularExpression(this->PatternToRegex(expr))); + this->Internals->Expressions.emplace_back(this->PatternToRegex(expr)); } void Glob::SetRelative(const char* dir) diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in index 73ea9db..9f2162b 100644 --- a/Source/kwsys/Process.h.in +++ b/Source/kwsys/Process.h.in @@ -180,8 +180,8 @@ kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, * write end of the pipe will be closed in the parent process and the * read end will be closed in the child process. */ -kwsysEXPORT void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, - kwsysProcess_Pipe_Handle p[2]); +kwsysEXPORT void kwsysProcess_SetPipeNative( + kwsysProcess* cp, int pipe, const kwsysProcess_Pipe_Handle p[2]); /** * Get/Set a possibly platform-specific option. Possible options are: diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index f65690b..5fde0b0 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -152,10 +152,11 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, static void kwsysProcessDestroy(kwsysProcess* cp); static int kwsysProcessSetupOutputPipeFile(int* p, const char* name); static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]); -static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, +static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, + const double* userTimeout, kwsysProcessTime* timeoutTime); static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, - double* userTimeout, + const double* userTimeout, kwsysProcessTimeNative* timeoutLength, int zeroIsExpired); static kwsysProcessTime kwsysProcessTimeGetCurrent(void); @@ -571,7 +572,7 @@ void kwsysProcess_SetPipeShared(kwsysProcess* cp, int prPipe, int shared) } } -void kwsysProcess_SetPipeNative(kwsysProcess* cp, int prPipe, int p[2]) +void kwsysProcess_SetPipeNative(kwsysProcess* cp, int prPipe, const int p[2]) { int* pPipeNative = 0; @@ -1959,7 +1960,8 @@ static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]) /* Get the time at which either the process or user timeout will expire. Returns 1 if the user timeout is first, and 0 otherwise. */ -static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, +static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, + const double* userTimeout, kwsysProcessTime* timeoutTime) { /* The first time this is called, we need to calculate the time at @@ -1991,7 +1993,7 @@ static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, /* 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, - double* userTimeout, + const double* userTimeout, kwsysProcessTimeNative* timeoutLength, int zeroIsExpired) { diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index 68c5218..56bbd20 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -761,7 +761,7 @@ void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared) } } -void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, HANDLE p[2]) +void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, const HANDLE p[2]) { HANDLE* pPipeNative = 0; diff --git a/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in index df7eb45..d11db88 100644 --- a/Source/kwsys/RegularExpression.hxx.in +++ b/Source/kwsys/RegularExpression.hxx.in @@ -66,16 +66,27 @@ private: const char* searchstring; }; +#ifdef _MSC_VER +# pragma warning(push) +# if _MSC_VER < 1900 +# pragma warning(disable : 4351) /* new behavior */ +# endif +#endif + /** * \brief Creates an invalid match object */ inline RegularExpressionMatch::RegularExpressionMatch() + : startp{} + , endp{} + , searchstring{} { - startp[0] = nullptr; - endp[0] = nullptr; - searchstring = nullptr; } +#ifdef _MSC_VER +# pragma warning(pop) +#endif + /** * \brief Returns true if the match pointers are valid */ diff --git a/Source/kwsys/System.c b/Source/kwsys/System.c index d43cc6f..dbfd2fd 100644 --- a/Source/kwsys/System.c +++ b/Source/kwsys/System.c @@ -22,7 +22,7 @@ typedef ptrdiff_t kwsysSystem_ptrdiff_t; typedef int kwsysSystem_ptrdiff_t; #endif -static int kwsysSystem__AppendByte(char* local, char** begin, char** end, +static int kwsysSystem__AppendByte(const char* local, char** begin, char** end, int* size, char c) { /* Allocate space for the character. */ diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index 6ec6e48..3cf64a8 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -132,7 +132,7 @@ typedef int siginfo_t; # endif # endif # if defined(KWSYS_CXX_HAS_RLIMIT64) -typedef struct rlimit64 ResourceLimitType; +using ResourceLimitType = struct rlimit64; # define GetResourceLimit getrlimit64 # else typedef struct rlimit ResourceLimitType; @@ -303,34 +303,34 @@ T min(T a, T b) } extern "C" { -typedef void (*SigAction)(int, siginfo_t*, void*); +using SigAction = void (*)(int, siginfo_t*, void*); } // Define SystemInformationImplementation class -typedef void (*DELAY_FUNC)(unsigned int uiMS); +using DELAY_FUNC = void (*)(unsigned int); class SystemInformationImplementation { public: - typedef SystemInformation::LongLong LongLong; + using LongLong = SystemInformation::LongLong; SystemInformationImplementation(); - ~SystemInformationImplementation(); + ~SystemInformationImplementation() = default; - const char* GetVendorString(); + const char* GetVendorString() const; const char* GetVendorID(); - std::string GetTypeID(); - std::string GetFamilyID(); - std::string GetModelID(); - std::string GetModelName(); - std::string GetSteppingCode(); - const char* GetExtendedProcessorName(); - const char* GetProcessorSerialNumber(); - int GetProcessorCacheSize(); - unsigned int GetLogicalProcessorsPerPhysical(); - float GetProcessorClockFrequency(); - int GetProcessorAPICID(); - int GetProcessorCacheXSize(long int); - bool DoesCPUSupportFeature(long int); + std::string GetTypeID() const; + std::string GetFamilyID() const; + std::string GetModelID() const; + std::string GetModelName() const; + std::string GetSteppingCode() const; + const char* GetExtendedProcessorName() const; + const char* GetProcessorSerialNumber() const; + int GetProcessorCacheSize() const; + unsigned int GetLogicalProcessorsPerPhysical() const; + float GetProcessorClockFrequency() const; + int GetProcessorAPICID() const; + int GetProcessorCacheXSize(long int) const; + bool DoesCPUSupportFeature(long int) const; const char* GetOSName(); const char* GetHostname(); @@ -339,24 +339,24 @@ public: const char* GetOSVersion(); const char* GetOSPlatform(); - bool Is64Bits(); + bool Is64Bits() const; - unsigned int GetNumberOfLogicalCPU(); // per physical cpu - unsigned int GetNumberOfPhysicalCPU(); + unsigned int GetNumberOfLogicalCPU() const; // per physical cpu + unsigned int GetNumberOfPhysicalCPU() const; bool DoesCPUSupportCPUID(); // Retrieve memory information in MiB. - size_t GetTotalVirtualMemory(); - size_t GetAvailableVirtualMemory(); - size_t GetTotalPhysicalMemory(); - size_t GetAvailablePhysicalMemory(); + size_t GetTotalVirtualMemory() const; + size_t GetAvailableVirtualMemory() const; + size_t GetTotalPhysicalMemory() const; + size_t GetAvailablePhysicalMemory() const; LongLong GetProcessId(); // Retrieve memory information in KiB. LongLong GetHostMemoryTotal(); - LongLong GetHostMemoryAvailable(const char* envVarName); + LongLong GetHostMemoryAvailable(const char* hostLimitEnvVarName); LongLong GetHostMemoryUsed(); LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName, @@ -377,60 +377,103 @@ public: void RunMemoryCheck(); public: - typedef struct tagID + using ID = struct tagID + { + int Type; + int Family; + int Model; + int Revision; + int ExtendedFamily; + int ExtendedModel; + std::string ProcessorName; + std::string Vendor; + std::string SerialNumber; + std::string ModelName; - } ID; + }; + + using CPUPowerManagement = struct tagCPUPowerManagement - typedef struct tagCPUPowerManagement { + bool HasVoltageID; + bool HasFrequencyID; + bool HasTempSenseDiode; - } CPUPowerManagement; + }; + + using CPUExtendedFeatures = struct tagCPUExtendedFeatures - typedef struct tagCPUExtendedFeatures { + bool Has3DNow; + bool Has3DNowPlus; + bool SupportsMP; + bool HasMMXPlus; + bool HasSSEMMX; + unsigned int LogicalProcessorsPerPhysical; + int APIC_ID; + CPUPowerManagement PowerManagement; - } CPUExtendedFeatures; + }; + + using CPUFeatures = struct CPUtagFeatures - typedef struct CPUtagFeatures { + bool HasFPU; + bool HasTSC; + bool HasMMX; + bool HasSSE; + bool HasSSEFP; + bool HasSSE2; + bool HasIA64; + bool HasAPIC; + bool HasCMOV; + bool HasMTRR; + bool HasACPI; + bool HasSerial; + bool HasThermal; + int CPUSpeed; + int L1CacheSize; + int L2CacheSize; + int L3CacheSize; + CPUExtendedFeatures ExtendedFeatures; - } CPUFeatures; + }; enum Manufacturer { @@ -476,7 +519,7 @@ protected: void CPUCountWindows(); // For windows unsigned char GetAPICId(); // For windows - bool IsSMTSupported(); + bool IsSMTSupported() const; static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); // For windows // For Linux and Cygwin, /proc/cpuinfo formats are slightly different @@ -885,7 +928,7 @@ int LoadLines(FILE* file, std::vector<std::string>& lines) *pBuf = '\0'; pBuf += 1; } - lines.push_back(buf); + lines.emplace_back(buf); ++nRead; } if (ferror(file)) { @@ -899,7 +942,7 @@ int LoadLines(FILE* file, std::vector<std::string>& lines) int LoadLines(const char* fileName, std::vector<std::string>& lines) { FILE* file = fopen(fileName, "r"); - if (file == 0) { + if (file == nullptr) { return 0; } int nRead = LoadLines(file, lines); @@ -1464,10 +1507,6 @@ SystemInformationImplementation::SystemInformationImplementation() this->OSIs64Bit = (sizeof(void*) == 8); } -SystemInformationImplementation::~SystemInformationImplementation() -{ -} - void SystemInformationImplementation::RunCPUCheck() { #ifdef _WIN32 @@ -1564,7 +1603,7 @@ void SystemInformationImplementation::RunMemoryCheck() } /** Get the vendor string */ -const char* SystemInformationImplementation::GetVendorString() +const char* SystemInformationImplementation::GetVendorString() const { return this->ChipID.Vendor.c_str(); } @@ -1760,7 +1799,7 @@ const char* SystemInformationImplementation::GetVendorID() } /** Return the type ID of the CPU */ -std::string SystemInformationImplementation::GetTypeID() +std::string SystemInformationImplementation::GetTypeID() const { std::ostringstream str; str << this->ChipID.Type; @@ -1768,7 +1807,7 @@ std::string SystemInformationImplementation::GetTypeID() } /** Return the family of the CPU present */ -std::string SystemInformationImplementation::GetFamilyID() +std::string SystemInformationImplementation::GetFamilyID() const { std::ostringstream str; str << this->ChipID.Family; @@ -1776,7 +1815,7 @@ std::string SystemInformationImplementation::GetFamilyID() } // Return the model of CPU present */ -std::string SystemInformationImplementation::GetModelID() +std::string SystemInformationImplementation::GetModelID() const { std::ostringstream str; str << this->ChipID.Model; @@ -1784,13 +1823,13 @@ std::string SystemInformationImplementation::GetModelID() } // Return the model name of CPU present */ -std::string SystemInformationImplementation::GetModelName() +std::string SystemInformationImplementation::GetModelName() const { return this->ChipID.ModelName; } /** Return the stepping code of the CPU present. */ -std::string SystemInformationImplementation::GetSteppingCode() +std::string SystemInformationImplementation::GetSteppingCode() const { std::ostringstream str; str << this->ChipID.Revision; @@ -1798,44 +1837,46 @@ std::string SystemInformationImplementation::GetSteppingCode() } /** Return the stepping code of the CPU present. */ -const char* SystemInformationImplementation::GetExtendedProcessorName() +const char* SystemInformationImplementation::GetExtendedProcessorName() const { return this->ChipID.ProcessorName.c_str(); } /** Return the serial number of the processor * in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */ -const char* SystemInformationImplementation::GetProcessorSerialNumber() +const char* SystemInformationImplementation::GetProcessorSerialNumber() const { return this->ChipID.SerialNumber.c_str(); } /** Return the logical processors per physical */ unsigned int SystemInformationImplementation::GetLogicalProcessorsPerPhysical() + const { return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical; } /** Return the processor clock frequency. */ -float SystemInformationImplementation::GetProcessorClockFrequency() +float SystemInformationImplementation::GetProcessorClockFrequency() const { return this->CPUSpeedInMHz; } /** Return the APIC ID. */ -int SystemInformationImplementation::GetProcessorAPICID() +int SystemInformationImplementation::GetProcessorAPICID() const { return this->Features.ExtendedFeatures.APIC_ID; } /** Return the L1 cache size. */ -int SystemInformationImplementation::GetProcessorCacheSize() +int SystemInformationImplementation::GetProcessorCacheSize() const { return this->Features.L1CacheSize; } /** Return the chosen cache size. */ -int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID) +int SystemInformationImplementation::GetProcessorCacheXSize( + long int dwCacheID) const { switch (dwCacheID) { case SystemInformation::CPU_FEATURE_L1CACHE: @@ -1848,7 +1889,8 @@ int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID) return -1; } -bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature) +bool SystemInformationImplementation::DoesCPUSupportFeature( + long int dwFeature) const { bool bHasFeature = false; @@ -3409,7 +3451,7 @@ bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() // We want to record the total number of cores in this->NumberOfPhysicalCPU // (checking only the first proc) std::string Cores = this->ExtractValueFromCpuInfoFile(buffer, "cpu cores"); - unsigned int NumberOfCoresPerSocket = (unsigned int)atoi(Cores.c_str()); + auto NumberOfCoresPerSocket = (unsigned int)atoi(Cores.c_str()); NumberOfCoresPerSocket = std::max(NumberOfCoresPerSocket, 1u); this->NumberOfPhysicalCPU = NumberOfCoresPerSocket * (unsigned int)NumberOfSockets; @@ -3441,7 +3483,7 @@ bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() // Linux Sparc: CPU speed is in Hz and encoded in hexadecimal CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "Cpu0ClkTck"); this->CPUSpeedInMHz = - static_cast<float>(strtoull(CPUSpeed.c_str(), 0, 16)) / 1000000.0f; + static_cast<float>(strtoull(CPUSpeed.c_str(), nullptr, 16)) / 1000000.0f; } #endif @@ -3502,9 +3544,8 @@ bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() cachename.push_back("D-cache"); // e.g. PA-RISC this->Features.L1CacheSize = 0; - for (size_t index = 0; index < cachename.size(); index++) { - std::string cacheSize = - this->ExtractValueFromCpuInfoFile(buffer, cachename[index]); + for (auto& index : cachename) { + std::string cacheSize = this->ExtractValueFromCpuInfoFile(buffer, index); if (!cacheSize.empty()) { pos = cacheSize.find(" KB"); if (pos != std::string::npos) { @@ -4249,24 +4290,24 @@ bool SystemInformationImplementation::QueryMemory() } /** */ -size_t SystemInformationImplementation::GetTotalVirtualMemory() +size_t SystemInformationImplementation::GetTotalVirtualMemory() const { return this->TotalVirtualMemory; } /** */ -size_t SystemInformationImplementation::GetAvailableVirtualMemory() +size_t SystemInformationImplementation::GetAvailableVirtualMemory() const { return this->AvailableVirtualMemory; } -size_t SystemInformationImplementation::GetTotalPhysicalMemory() +size_t SystemInformationImplementation::GetTotalPhysicalMemory() const { return this->TotalPhysicalMemory; } /** */ -size_t SystemInformationImplementation::GetAvailablePhysicalMemory() +size_t SystemInformationImplementation::GetAvailablePhysicalMemory() const { return this->AvailablePhysicalMemory; } @@ -4350,7 +4391,7 @@ void SystemInformationImplementation::DelayOverhead(unsigned int uiMS) } /** Works only for windows */ -bool SystemInformationImplementation::IsSMTSupported() +bool SystemInformationImplementation::IsSMTSupported() const { return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical > 1; } @@ -4432,13 +4473,13 @@ void SystemInformationImplementation::CPUCountWindows() } /** Return the number of logical CPUs on the system */ -unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU() +unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU() const { return this->NumberOfLogicalCPU; } /** Return the number of physical CPUs on the system */ -unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU() +unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU() const { return this->NumberOfPhysicalCPU; } @@ -4739,8 +4780,8 @@ std::string SystemInformationImplementation::ParseValueFromKStat( args.reserve(3 + args_string.size()); args.push_back("kstat"); args.push_back("-p"); - for (size_t i = 0; i < args_string.size(); ++i) { - args.push_back(args_string[i].c_str()); + for (auto& i : args_string) { + args.push_back(i.c_str()); } args.push_back(nullptr); @@ -5459,7 +5500,7 @@ void SystemInformationImplementation::TrimNewline(std::string& output) } /** Return true if the machine is 64 bits */ -bool SystemInformationImplementation::Is64Bits() +bool SystemInformationImplementation::Is64Bits() const { return this->OSIs64Bit; } diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index ce4d6ef..3fa1745 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -123,9 +123,9 @@ extern char** environ; #define VTK_URL_PROTOCOL_REGEX "([a-zA-Z0-9]*)://(.*)" #define VTK_URL_REGEX \ - "([a-zA-Z0-9]*)://(([A-Za-z0-9]+)(:([^:@]+))?@)?([^:@/]+)(:([0-9]+))?/" \ + "([a-zA-Z0-9]*)://(([A-Za-z0-9]+)(:([^:@]+))?@)?([^:@/]*)(:([0-9]+))?/" \ "(.+)?" - +#define VTK_URL_BYTE_REGEX "%[0-9a-fA-F][0-9a-fA-F]" #ifdef _MSC_VER # include <sys/utime.h> #else @@ -350,7 +350,7 @@ extern int putenv(char* __string) __THROW; namespace KWSYS_NAMESPACE { -double SystemTools::GetTime(void) +double SystemTools::GetTime() { #if defined(_WIN32) && !defined(__CYGWIN__) FILETIME ft; @@ -368,7 +368,7 @@ double SystemTools::GetTime(void) #if defined(_WIN32) typedef wchar_t envchar; #else -typedef char envchar; +using envchar = char; #endif /* Order by environment key only (VAR from VAR=VALUE). */ @@ -421,7 +421,7 @@ public: const envchar* Release(const envchar* env) { const envchar* old = nullptr; - iterator i = this->find(env); + auto i = this->find(env); if (i != this->end()) { old = *i; this->erase(i); @@ -452,7 +452,7 @@ struct SystemToolsPathCaseCmp class SystemToolsStatic { public: - typedef std::map<std::string, std::string> StringMap; + using StringMap = std::map<std::string, std::string>; #if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP /** * Path translation table from dir to refdir @@ -488,7 +488,7 @@ public: */ static std::string FindName( const std::string& name, - const std::vector<std::string>& path = std::vector<std::string>(), + const std::vector<std::string>& userPaths = std::vector<std::string>(), bool no_system_path = false); }; @@ -613,8 +613,7 @@ void SystemTools::GetPath(std::vector<std::string>& path, const char* env) done = true; } } - for (std::vector<std::string>::iterator i = path.begin() + old_size; - i != path.end(); ++i) { + for (auto i = path.begin() + old_size; i != path.end(); ++i) { SystemTools::ConvertToUnixSlashes(*i); } } @@ -1858,7 +1857,7 @@ char* SystemTools::DuplicateString(const char* str) // Return a cropped string std::string SystemTools::CropString(const std::string& s, size_t max_len) { - if (!s.size() || max_len == 0 || max_len >= s.size()) { + if (s.empty() || max_len == 0 || max_len >= s.size()) { return s; } @@ -1893,7 +1892,7 @@ std::vector<std::string> SystemTools::SplitString(const std::string& p, } if (isPath && path[0] == '/') { path.erase(path.begin()); - paths.push_back("/"); + paths.emplace_back("/"); } std::string::size_type pos1 = 0; std::string::size_type pos2 = path.find(sep, pos1 + 1); @@ -2186,12 +2185,15 @@ bool SystemTools::CopyFileIfDifferent(const std::string& source, // FilesDiffer does not handle file to directory compare if (SystemTools::FileIsDirectory(destination)) { const std::string new_destination = FileInDir(source, destination); - return SystemTools::CopyFileIfDifferent(source, new_destination); - } - // source and destination are files so do a copy if they - // are different - if (SystemTools::FilesDiffer(source, destination)) { - return SystemTools::CopyFileAlways(source, destination); + if (!SystemTools::ComparePath(new_destination, destination)) { + return SystemTools::CopyFileIfDifferent(source, new_destination); + } + } else { + // source and destination are files so do a copy if they + // are different + if (SystemTools::FilesDiffer(source, destination)) { + return SystemTools::CopyFileAlways(source, destination); + } } // at this point the files must be the same so return true return true; @@ -2326,14 +2328,8 @@ bool SystemTools::TextFilesDiffer(const std::string& path1, static bool CopyFileContentBlockwise(const std::string& source, const std::string& destination) { -// Open files -#if defined(_WIN32) - kwsys::ifstream fin( - Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source)).c_str(), - std::ios::in | std::ios::binary); -#else + // Open files kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary); -#endif if (!fin) { return false; } @@ -2344,14 +2340,8 @@ static bool CopyFileContentBlockwise(const std::string& source, // that do not allow file removal can be modified. SystemTools::RemoveFile(destination); -#if defined(_WIN32) - kwsys::ofstream fout( - Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(destination)).c_str(), - std::ios::out | std::ios::trunc | std::ios::binary); -#else kwsys::ofstream fout(destination.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); -#endif if (!fout) { return false; } @@ -3580,14 +3570,14 @@ void SystemTools::SplitPath(const std::string& p, for (; *last; ++last) { if (*last == '/' || *last == '\\') { // End of a component. Save it. - components.push_back(std::string(first, last)); + components.emplace_back(first, last); first = last + 1; } } // Save the last component unless there were no components. if (last != c) { - components.push_back(std::string(first, last)); + components.emplace_back(first, last); } } @@ -3603,7 +3593,7 @@ std::string SystemTools::JoinPath( // Construct result in a single string. std::string result; size_t len = 0; - for (std::vector<std::string>::const_iterator i = first; i != last; ++i) { + for (auto i = first; i != last; ++i) { len += 1 + i->size(); } result.reserve(len); @@ -3837,7 +3827,7 @@ SystemTools::FileTypeEnum SystemTools::DetectFileType(const char* filename, // Allocate buffer and read bytes - unsigned char* buffer = new unsigned char[length]; + auto* buffer = new unsigned char[length]; size_t read_length = fread(buffer, 1, length, fp); fclose(fp); if (read_length == 0) { @@ -4525,7 +4515,7 @@ std::string SystemTools::GetOperatingSystemNameAndVersion() bool SystemTools::ParseURLProtocol(const std::string& URL, std::string& protocol, - std::string& dataglom) + std::string& dataglom, bool decode) { // match 0 entire url // match 1 protocol @@ -4538,13 +4528,17 @@ bool SystemTools::ParseURLProtocol(const std::string& URL, protocol = urlRe.match(1); dataglom = urlRe.match(2); + if (decode) { + dataglom = DecodeURL(dataglom); + } + return true; } bool SystemTools::ParseURL(const std::string& URL, std::string& protocol, std::string& username, std::string& password, std::string& hostname, std::string& dataport, - std::string& database) + std::string& database, bool decode) { kwsys::RegularExpression urlRe(VTK_URL_REGEX); if (!urlRe.find(URL)) @@ -4568,9 +4562,35 @@ bool SystemTools::ParseURL(const std::string& URL, std::string& protocol, dataport = urlRe.match(8); database = urlRe.match(9); + if (decode) { + username = DecodeURL(username); + password = DecodeURL(password); + hostname = DecodeURL(hostname); + dataport = DecodeURL(dataport); + database = DecodeURL(database); + } + return true; } +// ---------------------------------------------------------------------- +std::string SystemTools::DecodeURL(const std::string& url) +{ + kwsys::RegularExpression urlByteRe(VTK_URL_BYTE_REGEX); + std::string ret; + for (size_t i = 0; i < url.length(); i++) { + if (urlByteRe.find(url.substr(i, 3))) { + ret += + static_cast<char>(strtoul(url.substr(i + 1, 2).c_str(), nullptr, 16)); + i += 2; + } else { + ret += url[i]; + } + } + return ret; +} + +// ---------------------------------------------------------------------- // These must NOT be initialized. Default initialization to zero is // necessary. static unsigned int SystemToolsManagerCount; @@ -4678,8 +4698,12 @@ void SystemTools::ClassFinalize() # include <stdlib.h> namespace KWSYS_NAMESPACE { -static int SystemToolsDebugReport(int, char* message, int*) +static int SystemToolsDebugReport(int, char* message, int* ret) { + if (ret) { + // Pretend user clicked on Retry button in popup. + *ret = 1; + } fprintf(stderr, "%s", message); fflush(stderr); return 1; // no further reporting required diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index c4ab9d4..d4a93fa 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -935,22 +935,32 @@ public: * Parse a character string : * protocol://dataglom * and fill protocol as appropriate. + * decode the dataglom using DecodeURL if set to true. * Return false if the URL does not have the required form, true otherwise. */ static bool ParseURLProtocol(const std::string& URL, std::string& protocol, - std::string& dataglom); + std::string& dataglom, bool decode = false); /** * Parse a string (a URL without protocol prefix) with the form: * protocol://[[username[':'password]'@']hostname[':'dataport]]'/'[datapath] * and fill protocol, username, password, hostname, dataport, and datapath * when values are found. + * decode all string except the protocol using DecodeUrl if set to true. * Return true if the string matches the format; false otherwise. */ static bool ParseURL(const std::string& URL, std::string& protocol, std::string& username, std::string& password, std::string& hostname, std::string& dataport, - std::string& datapath); + std::string& datapath, bool decode = false); + + /** + * Decode the percent-encoded string from an URL or an URI + * into their correct char values. + * Does not perform any other sort of validation. + * Return the decoded string + */ + static std::string DecodeURL(const std::string& url); private: /** diff --git a/Source/kwsys/Terminal.c b/Source/kwsys/Terminal.c index 4dd2461..4d1b46c 100644 --- a/Source/kwsys/Terminal.c +++ b/Source/kwsys/Terminal.c @@ -146,6 +146,7 @@ static const char* kwsysTerminalVT100Names[] = { "Eterm", "screen-bce", "screen-w", "screen.linux", + "st-256color", "tmux", "tmux-256color", "vt100", @@ -172,6 +173,14 @@ static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100, } } + /* GNU make 4.1+ may tell us that its output is destined for a TTY. */ + { + const char* termout = getenv("MAKE_TERMOUT"); + if (termout && *termout != '\0') { + return 1; + } + } + /* If running inside emacs the terminal is not VT100. Some emacs seem to claim the TERM is xterm even though they do not support VT100 escapes. */ diff --git a/Source/kwsys/kwsysPlatformTests.cmake b/Source/kwsys/kwsysPlatformTests.cmake index 28d3f68..89be4b8 100644 --- a/Source/kwsys/kwsysPlatformTests.cmake +++ b/Source/kwsys/kwsysPlatformTests.cmake @@ -1,185 +1,185 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing#kwsys for details. -SET(KWSYS_PLATFORM_TEST_FILE_C kwsysPlatformTestsC.c) -SET(KWSYS_PLATFORM_TEST_FILE_CXX kwsysPlatformTestsCXX.cxx) +set(KWSYS_PLATFORM_TEST_FILE_C kwsysPlatformTestsC.c) +set(KWSYS_PLATFORM_TEST_FILE_CXX kwsysPlatformTestsCXX.cxx) -MACRO(KWSYS_PLATFORM_TEST lang var description invert) - IF(NOT DEFINED ${var}_COMPILED) - MESSAGE(STATUS "${description}") +macro(KWSYS_PLATFORM_TEST lang var description invert) + if(NOT DEFINED ${var}_COMPILED) + message(STATUS "${description}") set(maybe_cxx_standard "") if(CMAKE_VERSION VERSION_LESS 3.8 AND CMAKE_CXX_STANDARD) set(maybe_cxx_standard "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}") endif() - TRY_COMPILE(${var}_COMPILED + try_compile(${var}_COMPILED ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS} CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=${KWSYS_PLATFORM_TEST_LINK_LIBRARIES}" ${maybe_cxx_standard} OUTPUT_VARIABLE OUTPUT) - IF(${var}_COMPILED) - FILE(APPEND + if(${var}_COMPILED) + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "${description} compiled with the following output:\n${OUTPUT}\n\n") - ELSE() - FILE(APPEND + else() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${description} failed to compile with the following output:\n${OUTPUT}\n\n") - ENDIF() - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - MESSAGE(STATUS "${description} - no") - ELSE() - MESSAGE(STATUS "${description} - yes") - ENDIF() - ELSE() - IF(${var}_COMPILED) - MESSAGE(STATUS "${description} - yes") - ELSE() - MESSAGE(STATUS "${description} - no") - ENDIF() - ENDIF() - ENDIF() - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - SET(${var} 0) - ELSE() - SET(${var} 1) - ENDIF() - ELSE() - IF(${var}_COMPILED) - SET(${var} 1) - ELSE() - SET(${var} 0) - ENDIF() - ENDIF() -ENDMACRO() + endif() + if(${invert} MATCHES INVERT) + if(${var}_COMPILED) + message(STATUS "${description} - no") + else() + message(STATUS "${description} - yes") + endif() + else() + if(${var}_COMPILED) + message(STATUS "${description} - yes") + else() + message(STATUS "${description} - no") + endif() + endif() + endif() + if(${invert} MATCHES INVERT) + if(${var}_COMPILED) + set(${var} 0) + else() + set(${var} 1) + endif() + else() + if(${var}_COMPILED) + set(${var} 1) + else() + set(${var} 0) + endif() + endif() +endmacro() -MACRO(KWSYS_PLATFORM_TEST_RUN lang var description invert) - IF(NOT DEFINED ${var}) - MESSAGE(STATUS "${description}") - TRY_RUN(${var} ${var}_COMPILED +macro(KWSYS_PLATFORM_TEST_RUN lang var description invert) + if(NOT DEFINED ${var}) + message(STATUS "${description}") + try_run(${var} ${var}_COMPILED ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS} OUTPUT_VARIABLE OUTPUT) # Note that ${var} will be a 0 return value on success. - IF(${var}_COMPILED) - IF(${var}) - FILE(APPEND + if(${var}_COMPILED) + if(${var}) + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${description} compiled but failed to run with the following output:\n${OUTPUT}\n\n") - ELSE() - FILE(APPEND + else() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "${description} compiled and ran with the following output:\n${OUTPUT}\n\n") - ENDIF() - ELSE() - FILE(APPEND + endif() + else() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${description} failed to compile with the following output:\n${OUTPUT}\n\n") - SET(${var} -1 CACHE INTERNAL "${description} failed to compile.") - ENDIF() + set(${var} -1 CACHE INTERNAL "${description} failed to compile.") + endif() - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - IF(${var}) - MESSAGE(STATUS "${description} - yes") - ELSE() - MESSAGE(STATUS "${description} - no") - ENDIF() - ELSE() - MESSAGE(STATUS "${description} - failed to compile") - ENDIF() - ELSE() - IF(${var}_COMPILED) - IF(${var}) - MESSAGE(STATUS "${description} - no") - ELSE() - MESSAGE(STATUS "${description} - yes") - ENDIF() - ELSE() - MESSAGE(STATUS "${description} - failed to compile") - ENDIF() - ENDIF() - ENDIF() + if(${invert} MATCHES INVERT) + if(${var}_COMPILED) + if(${var}) + message(STATUS "${description} - yes") + else() + message(STATUS "${description} - no") + endif() + else() + message(STATUS "${description} - failed to compile") + endif() + else() + if(${var}_COMPILED) + if(${var}) + message(STATUS "${description} - no") + else() + message(STATUS "${description} - yes") + endif() + else() + message(STATUS "${description} - failed to compile") + endif() + endif() + endif() - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - IF(${var}) - SET(${var} 1) - ELSE() - SET(${var} 0) - ENDIF() - ELSE() - SET(${var} 1) - ENDIF() - ELSE() - IF(${var}_COMPILED) - IF(${var}) - SET(${var} 0) - ELSE() - SET(${var} 1) - ENDIF() - ELSE() - SET(${var} 0) - ENDIF() - ENDIF() -ENDMACRO() + if(${invert} MATCHES INVERT) + if(${var}_COMPILED) + if(${var}) + set(${var} 1) + else() + set(${var} 0) + endif() + else() + set(${var} 1) + endif() + else() + if(${var}_COMPILED) + if(${var}) + set(${var} 0) + else() + set(${var} 1) + endif() + else() + set(${var} 0) + endif() + endif() +endmacro() -MACRO(KWSYS_PLATFORM_C_TEST var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS}) +macro(KWSYS_PLATFORM_C_TEST var description invert) + set(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES}) + set(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS}) KWSYS_PLATFORM_TEST(C "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) -ENDMACRO() + set(KWSYS_PLATFORM_TEST_DEFINES) + set(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) +endmacro() -MACRO(KWSYS_PLATFORM_C_TEST_RUN var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS}) +macro(KWSYS_PLATFORM_C_TEST_RUN var description invert) + set(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES}) + set(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS}) KWSYS_PLATFORM_TEST_RUN(C "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) -ENDMACRO() + set(KWSYS_PLATFORM_TEST_DEFINES) + set(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) +endmacro() -MACRO(KWSYS_PLATFORM_CXX_TEST var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS}) - SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES ${KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES}) +macro(KWSYS_PLATFORM_CXX_TEST var description invert) + set(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES}) + set(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS}) + set(KWSYS_PLATFORM_TEST_LINK_LIBRARIES ${KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES}) KWSYS_PLATFORM_TEST(CXX "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) - SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES) -ENDMACRO() + set(KWSYS_PLATFORM_TEST_DEFINES) + set(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) + set(KWSYS_PLATFORM_TEST_LINK_LIBRARIES) +endmacro() -MACRO(KWSYS_PLATFORM_CXX_TEST_RUN var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS}) +macro(KWSYS_PLATFORM_CXX_TEST_RUN var description invert) + set(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES}) + set(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS}) KWSYS_PLATFORM_TEST_RUN(CXX "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) -ENDMACRO() + set(KWSYS_PLATFORM_TEST_DEFINES) + set(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) +endmacro() #----------------------------------------------------------------------------- # KWSYS_PLATFORM_INFO_TEST(lang var description) # # Compile test named by ${var} and store INFO strings extracted from binary. -MACRO(KWSYS_PLATFORM_INFO_TEST lang var description) +macro(KWSYS_PLATFORM_INFO_TEST lang var description) # We can implement this macro on CMake 2.6 and above. - IF("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6) - SET(${var} "") - ELSE() + if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6) + set(${var} "") + else() # Choose a location for the result binary. - SET(KWSYS_PLATFORM_INFO_FILE + set(KWSYS_PLATFORM_INFO_FILE ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${var}.bin) # Compile the test binary. - IF(NOT EXISTS ${KWSYS_PLATFORM_INFO_FILE}) - MESSAGE(STATUS "${description}") - TRY_COMPILE(${var}_COMPILED + if(NOT EXISTS ${KWSYS_PLATFORM_INFO_FILE}) + message(STATUS "${description}") + try_compile(${var}_COMPILED ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} COMPILE_DEFINITIONS -DTEST_${var} @@ -188,29 +188,29 @@ MACRO(KWSYS_PLATFORM_INFO_TEST lang var description) OUTPUT_VARIABLE OUTPUT COPY_FILE ${KWSYS_PLATFORM_INFO_FILE} ) - IF(${var}_COMPILED) - FILE(APPEND + if(${var}_COMPILED) + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "${description} compiled with the following output:\n${OUTPUT}\n\n") - ELSE() - FILE(APPEND + else() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${description} failed to compile with the following output:\n${OUTPUT}\n\n") - ENDIF() - IF(${var}_COMPILED) - MESSAGE(STATUS "${description} - compiled") - ELSE() - MESSAGE(STATUS "${description} - failed") - ENDIF() - ENDIF() + endif() + if(${var}_COMPILED) + message(STATUS "${description} - compiled") + else() + message(STATUS "${description} - failed") + endif() + endif() # Parse info strings out of the compiled binary. - IF(${var}_COMPILED) - FILE(STRINGS ${KWSYS_PLATFORM_INFO_FILE} ${var} REGEX "INFO:[A-Za-z0-9]+\\[[^]]*\\]") - ELSE() - SET(${var} "") - ENDIF() + if(${var}_COMPILED) + file(STRINGS ${KWSYS_PLATFORM_INFO_FILE} ${var} REGEX "INFO:[A-Za-z0-9]+\\[[^]]*\\]") + else() + set(${var} "") + endif() - SET(KWSYS_PLATFORM_INFO_FILE) - ENDIF() -ENDMACRO() + set(KWSYS_PLATFORM_INFO_FILE) + endif() +endmacro() diff --git a/Source/kwsys/testCommandLineArguments.cxx b/Source/kwsys/testCommandLineArguments.cxx index 1778a9b..79ebe1a 100644 --- a/Source/kwsys/testCommandLineArguments.cxx +++ b/Source/kwsys/testCommandLineArguments.cxx @@ -98,7 +98,7 @@ int testCommandLineArguments(int argc, char* argv[]) std::vector<std::string> stl_strings_argument; std::string valid_stl_strings[] = { "ken", "brad", "bill", "andy" }; - typedef kwsys::CommandLineArguments argT; + using argT = kwsys::CommandLineArguments; arg.AddArgument("--some-int-variable", argT::SPACE_ARGUMENT, &some_int_variable, "Set some random int variable"); diff --git a/Source/kwsys/testCommandLineArguments1.cxx b/Source/kwsys/testCommandLineArguments1.cxx index 64561b1..cbc3002 100644 --- a/Source/kwsys/testCommandLineArguments1.cxx +++ b/Source/kwsys/testCommandLineArguments1.cxx @@ -25,7 +25,7 @@ int testCommandLineArguments1(int argc, char* argv[]) std::string p; int res = 0; - typedef kwsys::CommandLineArguments argT; + using argT = kwsys::CommandLineArguments; arg.AddArgument("-n", argT::SPACE_ARGUMENT, &n, "Argument N"); arg.AddArgument("-m", argT::EQUAL_ARGUMENT, &m, "Argument M"); arg.AddBooleanArgument("-p", &p, "Argument P"); diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx index 2421ac0..703ad4d 100644 --- a/Source/kwsys/testDynamicLoader.cxx +++ b/Source/kwsys/testDynamicLoader.cxx @@ -25,7 +25,7 @@ static std::string GetLibName(const char* lname, const char* subdir = nullptr) { // Construct proper name of lib std::string slname; - slname = EXECUTABLE_OUTPUT_PATH; + slname = RUNTIME_OUTPUT_DIRECTORY; if (subdir) { slname += "/"; slname += subdir; diff --git a/Source/kwsys/testEncoding.cxx b/Source/kwsys/testEncoding.cxx index 988697b..d672aed 100644 --- a/Source/kwsys/testEncoding.cxx +++ b/Source/kwsys/testEncoding.cxx @@ -85,7 +85,7 @@ static int testRobustEncoding() std::wstring wstr = kwsys::Encoding::ToWide(cstr); wstr = kwsys::Encoding::ToWide(nullptr); - if (wstr != L"") { + if (!wstr.empty()) { const wchar_t* wcstr = wstr.c_str(); std::cout << "ToWide(NULL) returned"; for (size_t i = 0; i < wstr.size(); i++) { @@ -95,7 +95,7 @@ static int testRobustEncoding() ret++; } wstr = kwsys::Encoding::ToWide(""); - if (wstr != L"") { + if (!wstr.empty()) { const wchar_t* wcstr = wstr.c_str(); std::cout << "ToWide(\"\") returned"; for (size_t i = 0; i < wstr.size(); i++) { @@ -113,13 +113,13 @@ static int testRobustEncoding() #endif std::string str = kwsys::Encoding::ToNarrow(nullptr); - if (str != "") { + if (!str.empty()) { std::cout << "ToNarrow(NULL) returned " << str << std::endl; ret++; } str = kwsys::Encoding::ToNarrow(L""); - if (wstr != L"") { + if (!wstr.empty()) { std::cout << "ToNarrow(\"\") returned " << str << std::endl; ret++; } @@ -140,14 +140,13 @@ static int testWithNulls() strings.push_back(std::string("k") + '\0' + '\0'); strings.push_back(std::string("\0\0\0\0", 4) + "lmn" + std::string("\0\0\0\0", 4)); - for (std::vector<std::string>::iterator it = strings.begin(); - it != strings.end(); ++it) { - std::wstring wstr = kwsys::Encoding::ToWide(*it); + for (auto& string : strings) { + std::wstring wstr = kwsys::Encoding::ToWide(string); std::string str = kwsys::Encoding::ToNarrow(wstr); - std::string s(*it); + std::string s(string); std::replace(s.begin(), s.end(), '\0', ' '); - std::cout << "'" << s << "' (" << it->size() << ")" << std::endl; - if (str != *it) { + std::cout << "'" << s << "' (" << string.size() << ")" << std::endl; + if (str != string) { std::replace(str.begin(), str.end(), '\0', ' '); std::cout << "string with null was different: '" << str << "' (" << str.size() << ")" << std::endl; diff --git a/Source/kwsys/testHashSTL.cxx b/Source/kwsys/testHashSTL.cxx index 4ed2f89..18cae7f 100644 --- a/Source/kwsys/testHashSTL.cxx +++ b/Source/kwsys/testHashSTL.cxx @@ -27,30 +27,30 @@ template class kwsys::hash_set<int>; static bool test_hash_map() { - typedef kwsys::hash_map<const char*, int> mtype; + using mtype = kwsys::hash_map<const char*, int>; mtype m; const char* keys[] = { "hello", "world" }; m[keys[0]] = 1; m.insert(mtype::value_type(keys[1], 2)); int sum = 0; - for (mtype::iterator mi = m.begin(); mi != m.end(); ++mi) { - std::cout << "Found entry [" << mi->first << "," << mi->second << "]" + for (auto& mi : m) { + std::cout << "Found entry [" << mi.first << "," << mi.second << "]" << std::endl; - sum += mi->second; + sum += mi.second; } return sum == 3; } static bool test_hash_set() { - typedef kwsys::hash_set<int> stype; + using stype = kwsys::hash_set<int>; stype s; s.insert(1); s.insert(2); int sum = 0; - for (stype::iterator si = s.begin(); si != s.end(); ++si) { - std::cout << "Found entry [" << *si << "]" << std::endl; - sum += *si; + for (int si : s) { + std::cout << "Found entry [" << si << "]" << std::endl; + sum += si; } return sum == 3; } diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index 1f3a15b..670e8dc 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -721,8 +721,7 @@ static std::string StringVectorToString(const std::vector<std::string>& vec) { std::stringstream ss; ss << "vector("; - for (std::vector<std::string>::const_iterator i = vec.begin(); - i != vec.end(); ++i) { + for (auto i = vec.begin(); i != vec.end(); ++i) { if (i != vec.begin()) { ss << ", "; } @@ -743,16 +742,16 @@ static bool CheckGetPath() const char* registryPath = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MyApp; MyKey]"; std::vector<std::string> originalPaths; - originalPaths.push_back(registryPath); + originalPaths.emplace_back(registryPath); std::vector<std::string> expectedPaths; - expectedPaths.push_back(registryPath); + expectedPaths.emplace_back(registryPath); #ifdef _WIN32 expectedPaths.push_back("C:/Somewhere/something"); expectedPaths.push_back("D:/Temp"); #else - expectedPaths.push_back("/Somewhere/something"); - expectedPaths.push_back("/tmp"); + expectedPaths.emplace_back("/Somewhere/something"); + expectedPaths.emplace_back("/tmp"); #endif bool res = true; @@ -817,7 +816,7 @@ static bool CheckFind() } std::vector<std::string> searchPaths; - searchPaths.push_back(TEST_SYSTEMTOOLS_BINARY_DIR); + searchPaths.emplace_back(TEST_SYSTEMTOOLS_BINARY_DIR); if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, true) .empty()) { std::cerr << "Problem with FindFile without system paths for: " @@ -1074,6 +1073,43 @@ static bool CheckCopyFileIfDifferent() } } + if (!kwsys::SystemTools::MakeDirectory("dir_a") || + !kwsys::SystemTools::MakeDirectory("dir_b")) { + return false; + } + + if (!kwsys::SystemTools::CopyFileIfDifferent("dir_a/", "dir_b")) { + ret = false; + } + + return ret; +} + +static bool CheckURLParsing() +{ + bool ret = true; + std::string url = "http://user:pw@hostname:42/full/url.com"; + + std::string protocol, username, password, hostname, dataport, database; + kwsys::SystemTools::ParseURL(url, protocol, username, password, hostname, + dataport, database); + if (protocol != "http" || username != "user" || password != "pw" || + hostname != "hostname" || dataport != "42" || + database != "full/url.com") { + std::cerr << "Incorrect URL parsing" << std::endl; + ret = false; + } + + std::string uri = + "file://hostname/path/to/" + "a%20file%20with%20str%C3%A0ng%C3%A8%20ch%40r%20and%20s%C2%B5aces"; + kwsys::SystemTools::ParseURL(uri, protocol, username, password, hostname, + dataport, database, true); + if (protocol != "file" || hostname != "hostname" || + database != "path/to/a file with stràngè ch@r and sµaces") { + std::cerr << "Incorrect URL parsing or decoding" << std::endl; + ret = false; + } return ret; } @@ -1124,5 +1160,7 @@ int testSystemTools(int, char* []) res &= CheckCopyFileIfDifferent(); + res &= CheckURLParsing(); + return res ? 0 : 1; } diff --git a/Source/kwsys/testSystemTools.h.in b/Source/kwsys/testSystemTools.h.in index 022e36e..e4b89a7 100644 --- a/Source/kwsys/testSystemTools.h.in +++ b/Source/kwsys/testSystemTools.h.in @@ -3,7 +3,7 @@ #ifndef @KWSYS_NAMESPACE@_testSystemtools_h #define @KWSYS_NAMESPACE@_testSystemtools_h -#define EXECUTABLE_OUTPUT_PATH "@CMAKE_CURRENT_BINARY_DIR@" +#define RUNTIME_OUTPUT_DIRECTORY "@CMAKE_CURRENT_BINARY_DIR@" #define TEST_SYSTEMTOOLS_SOURCE_DIR "@TEST_SYSTEMTOOLS_SOURCE_DIR@" #define TEST_SYSTEMTOOLS_BINARY_DIR "@TEST_SYSTEMTOOLS_BINARY_DIR@" |