diff options
Diffstat (limited to 'Source')
405 files changed, 10495 insertions, 10321 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index c57f71347..1b6bb00d4 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -1,9 +1,16 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. +# To ensure maximum portability across various compilers and platforms +# deactivate any compiler extensions +set(CMAKE_C_EXTENSIONS FALSE) +set(CMAKE_CXX_EXTENSIONS FALSE) + include(CheckIncludeFile) # Check if we can build support for ELF parsing. -if(CMAKE_CXX_PLATFORM_ID MATCHES "OpenBSD") +if(WIN32) + set(HAVE_ELF_H 0) +elseif(CMAKE_CXX_PLATFORM_ID MATCHES "OpenBSD") CHECK_INCLUDE_FILES("stdint.h;elf_abi.h" HAVE_ELF_H) else() CHECK_INCLUDE_FILE("elf.h" HAVE_ELF_H) @@ -354,6 +361,7 @@ set(SRCS cmMakefileTargetGenerator.cxx cmMakefileExecutableTargetGenerator.cxx cmMakefileLibraryTargetGenerator.cxx + cmMakefileProfilingData.cxx cmMakefileUtilityTargetGenerator.cxx cmMessageType.h cmMessenger.cxx @@ -377,8 +385,6 @@ set(SRCS cmProperty.h cmPropertyDefinition.cxx cmPropertyDefinition.h - cmPropertyDefinitionMap.cxx - cmPropertyDefinitionMap.h cmPropertyMap.cxx cmPropertyMap.h cmQtAutoGen.cxx @@ -486,6 +492,8 @@ set(SRCS cmBuildNameCommand.h cmCMakeHostSystemInformationCommand.cxx cmCMakeHostSystemInformationCommand.h + cmCMakeLanguageCommand.cxx + cmCMakeLanguageCommand.h cmCMakeMinimumRequired.cxx cmCMakeMinimumRequired.h cmCMakePolicyCommand.cxx @@ -690,7 +698,6 @@ set(SRCS cmWriteFileCommand.cxx cmWriteFileCommand.h - cm_static_string_view.hxx cm_get_date.h cm_get_date.c cm_utf8.h diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 661be1034..63a538ccb 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) -set(CMake_VERSION_MINOR 17) -set(CMake_VERSION_PATCH 5) +set(CMake_VERSION_MINOR 18) +set(CMake_VERSION_PATCH 0) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) @@ -21,7 +21,7 @@ endif() if(NOT CMake_VERSION_NO_GIT) # If this source was exported by 'git archive', use its commit info. - set(git_info [==[566e96d42d CMake 3.17.5]==]) + set(git_info [==[d421274e3e CMake 3.18.0]==]) # Otherwise, try to identify the current development source version. if(NOT git_info MATCHES "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]?[0-9a-f]?)[0-9a-f]* " diff --git a/Source/CPack/IFW/cmCPackIFWCommon.cxx b/Source/CPack/IFW/cmCPackIFWCommon.cxx index 9fa74be76..20d392d21 100644 --- a/Source/CPack/IFW/cmCPackIFWCommon.cxx +++ b/Source/CPack/IFW/cmCPackIFWCommon.cxx @@ -2,7 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCPackIFWCommon.h" -#include <cstddef> +#include <cstddef> // IWYU pragma: keep #include <sstream> #include <utility> #include <vector> diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx index 509ac6507..2806c614e 100644 --- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx +++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx @@ -544,10 +544,7 @@ std::string cmCPackIFWGenerator::GetGroupPackageName( if (group->ParentGroup) { cmCPackIFWPackage* package = this->GetGroupPackage(group->ParentGroup); bool dot = !this->ResolveDuplicateNames; - if (dot && name.substr(0, package->Name.size()) == package->Name) { - dot = false; - } - if (dot) { + if (dot && !cmHasPrefix(name, package->Name)) { name = package->Name + "." + name; } } @@ -576,10 +573,7 @@ std::string cmCPackIFWGenerator::GetComponentPackageName( return package->Name; } bool dot = !this->ResolveDuplicateNames; - if (dot && name.substr(0, package->Name.size()) == package->Name) { - dot = false; - } - if (dot) { + if (dot && !cmHasPrefix(name, package->Name)) { name = package->Name + "." + name; } } diff --git a/Source/CPack/IFW/cmCPackIFWPackage.cxx b/Source/CPack/IFW/cmCPackIFWPackage.cxx index 9a9cd5678..56a74c58b 100644 --- a/Source/CPack/IFW/cmCPackIFWPackage.cxx +++ b/Source/CPack/IFW/cmCPackIFWPackage.cxx @@ -55,8 +55,7 @@ cmCPackIFWPackage::DependenceStruct::DependenceStruct( if (dashPos != std::string::npos) { pos = dashPos; } - this->Name = - pos == std::string::npos ? dependence : dependence.substr(0, pos); + this->Name = dependence.substr(0, pos); } std::string cmCPackIFWPackage::DependenceStruct::NameWithCompare() const diff --git a/Source/CPack/IFW/cmCPackIFWRepository.cxx b/Source/CPack/IFW/cmCPackIFWRepository.cxx index a6965491e..f5e87443b 100644 --- a/Source/CPack/IFW/cmCPackIFWRepository.cxx +++ b/Source/CPack/IFW/cmCPackIFWRepository.cxx @@ -21,11 +21,7 @@ bool cmCPackIFWRepository::IsValid() const switch (this->Update) { case cmCPackIFWRepository::None: - valid = !this->Url.empty(); - break; case cmCPackIFWRepository::Add: - valid = !this->Url.empty(); - break; case cmCPackIFWRepository::Remove: valid = !this->Url.empty(); break; diff --git a/Source/CPack/OSXScriptLauncher.cxx b/Source/CPack/OSXScriptLauncher.cxx index 21d27a02d..bdaf779af 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 e71a38fd2..72af10b3c 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -4,14 +4,15 @@ #include <algorithm> +#include <cm/memory> #include <cm/string_view> +#include <cmext/algorithm> #include "cmsys/Directory.hxx" #include "cmsys/Encoding.hxx" #include "cmsys/FStream.hxx" #include "cmsys/SystemTools.hxx" -#include "cmAlgorithms.h" #include "cmCPackComponentGroup.h" #include "cmCPackLog.h" #include "cmCryptoHash.h" @@ -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(); } @@ -103,7 +98,7 @@ bool cmCPackWIXGenerator::RunCandleCommand(std::string const& sourceFile, command << " -ext " << QuotePath(ext); } - if (sourceFile.rfind(this->CPackTopLevel, 0) != 0) { + if (!cmHasSuffix(sourceFile, this->CPackTopLevel)) { command << " " << QuotePath("-I" + this->CPackTopLevel); } @@ -355,8 +350,7 @@ void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile() std::vector<std::string> options = GetOptions(); for (std::string const& name : options) { - if (name.length() > prefix.length() && - name.substr(0, prefix.length()) == prefix) { + if (cmHasPrefix(name, prefix)) { std::string id = name.substr(prefix.length()); std::string value = GetOption(name.c_str()); @@ -960,7 +954,7 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitions( shortcut.workingDirectoryId = directoryId; shortcuts.insert(cmWIXShortcuts::START_MENU, id, shortcut); - if (cmContains(desktopExecutables, executableName)) { + if (cm::contains(desktopExecutables, executableName)) { shortcuts.insert(cmWIXShortcuts::DESKTOP, id, shortcut); } } @@ -1104,14 +1098,14 @@ std::string cmCPackWIXGenerator::CreateHashedId( cmCryptoHash sha1(cmCryptoHash::AlgoSHA1); std::string const hash = sha1.HashString(path); - std::string identifier = cmStrCat(cm::string_view(hash).substr(0, 7), '_'); - const size_t maxFileNameLength = 52; + std::string identifier = + cmStrCat(cm::string_view(hash).substr(0, 7), '_', + cm::string_view(normalizedFilename).substr(0, maxFileNameLength)); + + // if the name was truncated if (normalizedFilename.length() > maxFileNameLength) { - identifier += normalizedFilename.substr(0, maxFileNameLength - 3); identifier += "..."; - } else { - identifier += normalizedFilename; } return identifier; diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h index d1933483f..d5a16ec05 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/cmWIXAccessControlList.cxx b/Source/CPack/WiX/cmWIXAccessControlList.cxx index 3668b4613..9685a7f49 100644 --- a/Source/CPack/WiX/cmWIXAccessControlList.cxx +++ b/Source/CPack/WiX/cmWIXAccessControlList.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmWIXAccessControlList.h" +#include <cm/string_view> + #include "cmCPackGenerator.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -35,12 +37,13 @@ void cmWIXAccessControlList::CreatePermissionElement(std::string const& entry) return; } - std::string user_and_domain = entry.substr(0, pos); - std::string permission_string = entry.substr(pos + 1); + cm::string_view enview(entry); + cm::string_view user_and_domain = enview.substr(0, pos); + cm::string_view permission_string = enview.substr(pos + 1); pos = user_and_domain.find('@'); - std::string user; - std::string domain; + cm::string_view user; + cm::string_view domain; if (pos != std::string::npos) { user = user_and_domain.substr(0, pos); domain = user_and_domain.substr(pos + 1); @@ -51,9 +54,9 @@ void cmWIXAccessControlList::CreatePermissionElement(std::string const& entry) std::vector<std::string> permissions = cmTokenize(permission_string, ","); this->SourceWriter.BeginElement("Permission"); - this->SourceWriter.AddAttribute("User", user); + this->SourceWriter.AddAttribute("User", std::string(user)); if (!domain.empty()) { - this->SourceWriter.AddAttribute("Domain", domain); + this->SourceWriter.AddAttribute("Domain", std::string(domain)); } for (std::string const& permission : permissions) { this->EmitBooleanAttribute(entry, cmTrimWhitespace(permission)); diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx index c0d879a0c..b4085d5b8 100644 --- a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx +++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx @@ -1,5 +1,10 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ +#if defined(__CYGWIN__) +// For S_IWRITE symbol +# define _DEFAULT_SOURCE +#endif + #include "cmWIXFilesSourceWriter.h" #include "cm_sys_stat.h" diff --git a/Source/CPack/WiX/cmWIXPatch.cxx b/Source/CPack/WiX/cmWIXPatch.cxx index ca232f94b..122ffaff5 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 fd9103bc1..8b26c4eec 100644 --- a/Source/CPack/WiX/cmWIXPatchParser.cxx +++ b/Source/CPack/WiX/cmWIXPatchParser.cxx @@ -2,7 +2,11 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmWIXPatchParser.h" -#include "cm_expat.h" +#include <utility> + +#include <cm/memory> + +#include <cm3p/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 87dd89288..8d5d2adc4 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/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx index 43f2946bd..967cc6060 100644 --- a/Source/CPack/cmCPackArchiveGenerator.cxx +++ b/Source/CPack/cmCPackArchiveGenerator.cxx @@ -8,6 +8,8 @@ #include <utility> #include <vector> +#include <cm3p/archive.h> + #include "cmCPackComponentGroup.h" #include "cmCPackGenerator.h" #include "cmCPackLog.h" @@ -154,6 +156,20 @@ int cmCPackArchiveGenerator::addOneComponentToArchive( } \ cmArchiveWrite archive(gf, this->Compress, this->ArchiveFormat); \ do { \ + if (!this->SetArchiveOptions(&archive)) { \ + cmCPackLogger(cmCPackLog::LOG_ERROR, \ + "Problem to set archive options <" \ + << (filename) << ">, ERROR = " << (archive).GetError() \ + << std::endl); \ + return 0; \ + } \ + if (!archive.Open()) { \ + cmCPackLogger(cmCPackLog::LOG_ERROR, \ + "Problem to open archive <" \ + << (filename) << ">, ERROR = " << (archive).GetError() \ + << std::endl); \ + return 0; \ + } \ if (!(archive)) { \ cmCPackLogger(cmCPackLog::LOG_ERROR, \ "Problem to create archive <" \ @@ -328,3 +344,23 @@ bool cmCPackArchiveGenerator::SupportsComponentInstallation() const // (for backward compatibility reason) return IsOn("CPACK_ARCHIVE_COMPONENT_INSTALL"); } + +bool cmCPackArchiveGenerator::SetArchiveOptions(cmArchiveWrite* archive) +{ +#if ARCHIVE_VERSION_NUMBER >= 3004000 + // Upstream fixed an issue with their integer parsing in 3.4.0 which would + // cause spurious errors to be raised from `strtoull`. + if (this->Compress == cmArchiveWrite::CompressXZ) { + const char* threads = "1"; + if (this->IsSet("CPACK_ARCHIVE_THREADS")) { + threads = this->GetOption("CPACK_ARCHIVE_THREADS"); + } + + if (!archive->SetFilterOption("xz", "threads", threads)) { + return false; + } + } +#endif + + return true; +} diff --git a/Source/CPack/cmCPackArchiveGenerator.h b/Source/CPack/cmCPackArchiveGenerator.h index 8d677208f..7eb566597 100644 --- a/Source/CPack/cmCPackArchiveGenerator.h +++ b/Source/CPack/cmCPackArchiveGenerator.h @@ -86,6 +86,8 @@ private: return this->OutputExtension.c_str(); } + bool SetArchiveOptions(cmArchiveWrite* archive); + private: cmArchiveWrite::Compress Compress; std::string ArchiveFormat; diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index d92acdebf..3d5fe6b9d 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -135,16 +135,17 @@ void DebGenerator::generateDebianBinaryFile() const { // debian-binary file const std::string dbfilename = WorkDir + "/debian-binary"; - cmGeneratedFileStream out(dbfilename); - out << "2.0"; - out << std::endl; // required for valid debian package + cmGeneratedFileStream out; + out.Open(dbfilename, false, true); + out << "2.0\n"; // required for valid debian package } void DebGenerator::generateControlFile() const { std::string ctlfilename = WorkDir + "/control"; - cmGeneratedFileStream out(ctlfilename); + cmGeneratedFileStream out; + out.Open(ctlfilename, false, true); for (auto const& kv : ControlValues) { out << kv.first << ": " << kv.second << "\n"; } @@ -156,8 +157,7 @@ void DebGenerator::generateControlFile() const totalSize += cmSystemTools::FileLength(file); } } - out << "Installed-Size: " << (totalSize + 1023) / 1024 << "\n"; - out << std::endl; + out << "Installed-Size: " << (totalSize + 1023) / 1024 << "\n\n"; } bool DebGenerator::generateDataTar() const @@ -173,6 +173,7 @@ bool DebGenerator::generateDataTar() const } cmArchiveWrite data_tar(fileStream_data_tar, TarCompressionType, DebianArchiveType); + data_tar.Open(); // uid/gid should be the one of the root user, and this root user has // always uid/gid equal to 0. @@ -247,7 +248,8 @@ std::string DebGenerator::generateMD5File() const { std::string md5filename = WorkDir + "/md5sums"; - cmGeneratedFileStream out(md5filename); + cmGeneratedFileStream out; + out.Open(md5filename, false, true); std::string topLevelWithTrailingSlash = cmStrCat(TemporaryDir, '/'); for (std::string const& file : PackageFiles) { @@ -291,6 +293,7 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const } cmArchiveWrite control_tar(fileStream_control_tar, cmArchiveWrite::CompressGZip, DebianArchiveType); + control_tar.Open(); // sets permissions and uid/gid for the files control_tar.SetUIDAndGID(0u, 0u); @@ -410,6 +413,7 @@ bool DebGenerator::generateDeb() const cmGeneratedFileStream debStream; debStream.Open(outputPath, false, true); cmArchiveWrite deb(debStream, cmArchiveWrite::CompressNone, "arbsd"); + deb.Open(); // uid/gid should be the one of the root user, and this root user has // always uid/gid equal to 0. @@ -754,15 +758,17 @@ int cmCPackDebGenerator::createDeb() const bool gen_shibs = this->IsOn("CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS") && debian_pkg_shlibs && *debian_pkg_shlibs; if (gen_shibs) { - cmGeneratedFileStream out(shlibsfilename); + cmGeneratedFileStream out; + out.Open(shlibsfilename, false, true); out << debian_pkg_shlibs; - out << std::endl; + out << '\n'; } const std::string postinst = strGenWDIR + "/postinst"; const std::string postrm = strGenWDIR + "/postrm"; if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST")) { - cmGeneratedFileStream out(postinst); + cmGeneratedFileStream out; + out.Open(postinst, false, true); out << "#!/bin/sh\n\n" "set -e\n\n" "if [ \"$1\" = \"configure\" ]; then\n" @@ -770,7 +776,8 @@ int cmCPackDebGenerator::createDeb() "fi\n"; } if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM")) { - cmGeneratedFileStream out(postrm); + cmGeneratedFileStream out; + out.Open(postrm, false, true); out << "#!/bin/sh\n\n" "set -e\n\n" "if [ \"$1\" = \"remove\" ]; then\n" diff --git a/Source/CPack/cmCPackExternalGenerator.cxx b/Source/CPack/cmCPackExternalGenerator.cxx index 142eb6fbf..11e1aecce 100644 --- a/Source/CPack/cmCPackExternalGenerator.cxx +++ b/Source/CPack/cmCPackExternalGenerator.cxx @@ -8,10 +8,10 @@ #include <cm/memory> -#include "cmsys/FStream.hxx" +#include <cm3p/json/value.h> +#include <cm3p/json/writer.h> -#include "cm_jsoncpp_value.h" -#include "cm_jsoncpp_writer.h" +#include "cmsys/FStream.hxx" #include "cmCPackComponentGroup.h" #include "cmCPackLog.h" diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx index e3cc352fb..b673006f2 100644 --- a/Source/CPack/cmCPackFreeBSDGenerator.cxx +++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx @@ -8,6 +8,7 @@ #include "cmGeneratedFileStream.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmWorkingDirectory.h" // Needed for ::open() and ::stat() #include <algorithm> @@ -285,8 +286,7 @@ int cmCPackFreeBSDGenerator::PackageFiles() } std::vector<std::string>::const_iterator fileIt; - std::string dir = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(toplevel); + cmWorkingDirectory wd(toplevel); files.erase(std::remove_if(files.begin(), files.end(), ignore_file), files.end()); @@ -332,6 +332,5 @@ int cmCPackFreeBSDGenerator::PackageFiles() } } - cmSystemTools::ChangeDirectory(dir); return 1; } diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index e0531442f..288dc58a7 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -403,7 +403,6 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( } /* rebuild symlinks in the installed tree */ if (!symlinkedFiles.empty()) { - std::string curDir = cmSystemTools::GetCurrentWorkingDirectory(); std::string goToDir = cmStrCat(tempDir, '/', subdir); cmCPackLogger(cmCPackLog::LOG_DEBUG, "Change dir to: " << goToDir << std::endl); @@ -442,7 +441,8 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( } } cmCPackLogger(cmCPackLog::LOG_DEBUG, - "Going back to: " << curDir << std::endl); + "Going back to: " << workdir.GetOldDirectory() + << std::endl); } } } @@ -921,11 +921,11 @@ int cmCPackGenerator::InstallCMakeProject( } } - if (nullptr != mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) { + if (auto d = mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) { if (!absoluteDestFiles.empty()) { absoluteDestFiles += ";"; } - absoluteDestFiles += mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES"); + absoluteDestFiles += d; cmCPackLogger(cmCPackLog::LOG_DEBUG, "Got some ABSOLUTE DESTINATION FILES: " << absoluteDestFiles << std::endl); @@ -936,8 +936,7 @@ int cmCPackGenerator::InstallCMakeProject( GetComponentInstallDirNameSuffix(component); if (nullptr != this->GetOption(absoluteDestFileComponent)) { std::string absoluteDestFilesListComponent = - cmStrCat(this->GetOption(absoluteDestFileComponent), ';', - mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")); + cmStrCat(this->GetOption(absoluteDestFileComponent), ';', d); this->SetOption(absoluteDestFileComponent, absoluteDestFilesListComponent.c_str()); } else { diff --git a/Source/CPack/cmCPackLog.cxx b/Source/CPack/cmCPackLog.cxx index ca675fdc8..49e411393 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 1cb16433c..68ffccee9 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 2a4662798..058b090e0 100644 --- a/Source/CPack/cmCPackNSISGenerator.cxx +++ b/Source/CPack/cmCPackNSISGenerator.cxx @@ -9,10 +9,11 @@ #include <sstream> #include <utility> +#include <cmext/algorithm> + #include "cmsys/Directory.hxx" #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmCPackComponentGroup.h" #include "cmCPackGenerator.h" #include "cmCPackLog.h" @@ -68,7 +69,7 @@ int cmCPackNSISGenerator::PackageFiles() // Use the custom component install directory if we have one if (pos != std::string::npos) { - const std::string componentName = fileN.substr(0, pos); + auto componentName = cm::string_view(fileN).substr(0, pos); outputDir = CustomComponentInstallDirectory(componentName); } else { outputDir = CustomComponentInstallDirectory(fileN); @@ -103,7 +104,7 @@ int cmCPackNSISGenerator::PackageFiles() componentName = fileN.substr(0, slash); // Strip off the component part of the path. - fileN = fileN.substr(slash + 1); + fileN.erase(0, slash + 1); } } std::replace(fileN.begin(), fileN.end(), '/', '\\'); @@ -203,6 +204,11 @@ int cmCPackNSISGenerator::PackageFiles() "!define MUI_FINISHPAGE_TITLE_3LINES"); } + if (this->IsSet("CPACK_NSIS_MANIFEST_DPI_AWARE")) { + this->SetOptionIfNotSet("CPACK_NSIS_MANIFEST_DPI_AWARE_CODE", + "ManifestDPIAware true"); + } + // Setup all of the component sections if (this->Components.empty()) { this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES", ""); @@ -524,7 +530,7 @@ int cmCPackNSISGenerator::InitializeInternal() << ".lnk\"" << std::endl; // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on // if so add a desktop link - if (cmContains(cpackPackageDesktopLinksVector, execName)) { + if (cm::contains(cpackPackageDesktopLinksVector, execName)) { str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n"; str << " CreateShortCut \"$DESKTOP\\" << linkName << R"(.lnk" "$INSTDIR\)" << cpackNsisExecutablesDirectory << "\\" @@ -672,7 +678,7 @@ std::string cmCPackNSISGenerator::CreateComponentDescription( const std::string componentOutputDir = CustomComponentInstallDirectory(component->Name); - componentCode += " SetOutPath \"" + componentOutputDir + "\"\n"; + componentCode += cmStrCat(" SetOutPath \"", componentOutputDir, "\"\n"); // Create the actual installation commands if (component->IsDownloaded) { @@ -921,12 +927,11 @@ std::string cmCPackNSISGenerator::CreateComponentGroupDescription( } std::string cmCPackNSISGenerator::CustomComponentInstallDirectory( - const std::string& componentName) + cm::string_view componentName) { - const char* outputDir = - this->GetOption("CPACK_NSIS_" + componentName + "_INSTALL_DIRECTORY"); - const std::string componentOutputDir = (outputDir ? outputDir : "$INSTDIR"); - return componentOutputDir; + const char* outputDir = this->GetOption( + cmStrCat("CPACK_NSIS_", componentName, "_INSTALL_DIRECTORY")); + return outputDir ? outputDir : "$INSTDIR"; } std::string cmCPackNSISGenerator::TranslateNewlines(std::string str) diff --git a/Source/CPack/cmCPackNSISGenerator.h b/Source/CPack/cmCPackNSISGenerator.h index 0af37af50..88cba45e8 100644 --- a/Source/CPack/cmCPackNSISGenerator.h +++ b/Source/CPack/cmCPackNSISGenerator.h @@ -10,6 +10,8 @@ #include <string> #include <vector> +#include <cm/string_view> + #include "cmCPackGenerator.h" class cmCPackComponent; @@ -75,8 +77,7 @@ protected: /// Returns the custom install directory if available for the specified /// component, otherwise $INSTDIR is returned. - std::string CustomComponentInstallDirectory( - const std::string& componentName); + std::string CustomComponentInstallDirectory(cm::string_view componentName); /// Translations any newlines found in the string into \\r\\n, so that the /// resulting string can be used within NSIS. diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx index dc316233c..3a400b7db 100644 --- a/Source/CPack/cpack.cxx +++ b/Source/CPack/cpack.cxx @@ -85,7 +85,7 @@ int cpackDefinitionArgument(const char* argument, const char* cValue, return 0; } std::string key = value.substr(0, pos); - value = value.substr(pos + 1); + value.erase(0, pos + 1); def->Map[key] = value; cmCPack_Log(def->Log, cmCPackLog::LOG_DEBUG, "Set CPack variable: " << key << " to \"" << value << "\"" @@ -312,7 +312,7 @@ int main(int argc, char const* const* argv) // The value has not been set on the command line else { // get a default value (current working directory) - cpackProjectDirectory = cmsys::SystemTools::GetCurrentWorkingDirectory(); + cpackProjectDirectory = cmSystemTools::GetCurrentWorkingDirectory(); // use default value if no value has been provided by the config file if (!globalMF.IsSet("CPACK_PACKAGE_DIRECTORY")) { globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY", diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx index c87fb83b3..c533cd7f9 100644 --- a/Source/CTest/cmCTestBZR.cxx +++ b/Source/CTest/cmCTestBZR.cxx @@ -10,9 +10,9 @@ #include <cmext/algorithm> -#include "cmsys/RegularExpression.hxx" +#include <cm3p/expat.h> -#include "cm_expat.h" +#include "cmsys/RegularExpression.hxx" #include "cmCTest.h" #include "cmCTestVC.h" diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index 5e29386c7..db426b2ff 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -379,7 +379,7 @@ int cmCTestBuildAndTestHandler::ProcessCommandLineArguments( const std::vector<std::string>& allArgs) { // --build-and-test options - if (currentArg.find("--build-and-test", 0) == 0 && + if (cmHasLiteralPrefix(currentArg, "--build-and-test") && idx < allArgs.size() - 1) { if (idx + 2 < allArgs.size()) { idx++; @@ -397,25 +397,29 @@ int cmCTestBuildAndTestHandler::ProcessCommandLineArguments( return 0; } } - if (currentArg.find("--build-target", 0) == 0 && idx < allArgs.size() - 1) { + if (cmHasLiteralPrefix(currentArg, "--build-target") && + idx < allArgs.size() - 1) { idx++; this->BuildTargets.push_back(allArgs[idx]); } - if (currentArg.find("--build-nocmake", 0) == 0) { + if (cmHasLiteralPrefix(currentArg, "--build-nocmake")) { this->BuildNoCMake = true; } - if (currentArg.find("--build-run-dir", 0) == 0 && idx < allArgs.size() - 1) { + if (cmHasLiteralPrefix(currentArg, "--build-run-dir") && + idx < allArgs.size() - 1) { idx++; this->BuildRunDir = allArgs[idx]; } - if (currentArg.find("--build-two-config", 0) == 0) { + if (cmHasLiteralPrefix(currentArg, "--build-two-config")) { this->BuildTwoConfig = true; } - if (currentArg.find("--build-exe-dir", 0) == 0 && idx < allArgs.size() - 1) { + if (cmHasLiteralPrefix(currentArg, "--build-exe-dir") && + idx < allArgs.size() - 1) { idx++; this->ExecutableDirectory = allArgs[idx]; } - if (currentArg.find("--test-timeout", 0) == 0 && idx < allArgs.size() - 1) { + if (cmHasLiteralPrefix(currentArg, "--test-timeout") && + idx < allArgs.size() - 1) { idx++; this->Timeout = cmDuration(atof(allArgs[idx].c_str())); } @@ -431,31 +435,33 @@ int cmCTestBuildAndTestHandler::ProcessCommandLineArguments( idx++; this->BuildGeneratorToolset = allArgs[idx]; } - if (currentArg.find("--build-project", 0) == 0 && idx < allArgs.size() - 1) { + if (cmHasLiteralPrefix(currentArg, "--build-project") && + idx < allArgs.size() - 1) { idx++; this->BuildProject = allArgs[idx]; } - if (currentArg.find("--build-makeprogram", 0) == 0 && + if (cmHasLiteralPrefix(currentArg, "--build-makeprogram") && idx < allArgs.size() - 1) { idx++; this->BuildMakeProgram = allArgs[idx]; } - if (currentArg.find("--build-config-sample", 0) == 0 && + if (cmHasLiteralPrefix(currentArg, "--build-config-sample") && idx < allArgs.size() - 1) { idx++; this->ConfigSample = allArgs[idx]; } - if (currentArg.find("--build-noclean", 0) == 0) { + if (cmHasLiteralPrefix(currentArg, "--build-noclean")) { this->BuildNoClean = true; } - if (currentArg.find("--build-options", 0) == 0) { + if (cmHasLiteralPrefix(currentArg, "--build-options")) { while (idx + 1 < allArgs.size() && allArgs[idx + 1] != "--build-target" && allArgs[idx + 1] != "--test-command") { ++idx; this->BuildOptions.push_back(allArgs[idx]); } } - if (currentArg.find("--test-command", 0) == 0 && idx < allArgs.size() - 1) { + if (cmHasLiteralPrefix(currentArg, "--test-command") && + idx < allArgs.size() - 1) { ++idx; this->TestCommand = allArgs[idx]; while (idx + 1 < allArgs.size()) { diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx index d1b7701ec..44fdc2945 100644 --- a/Source/CTest/cmCTestBuildCommand.cxx +++ b/Source/CTest/cmCTestBuildCommand.cxx @@ -5,7 +5,7 @@ #include <cstring> #include <sstream> -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmCTest.h" #include "cmCTestBuildHandler.h" diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index 03a3fd306..35c2b1118 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -386,24 +386,20 @@ int cmCTestBuildHandler::ProcessHandler() if (this->CTest->GetCTestConfiguration("SourceDirectory").size() > 20) { std::string srcdir = this->CTest->GetCTestConfiguration("SourceDirectory") + "/"; - for (cc = srcdir.size() - 2; cc > 0; cc--) { - if (srcdir[cc] == '/') { - srcdir = srcdir.substr(0, cc + 1); - break; - } + cc = srcdir.rfind('/', srcdir.size() - 2); + if (cc != std::string::npos) { + srcdir.resize(cc + 1); + this->SimplifySourceDir = std::move(srcdir); } - this->SimplifySourceDir = srcdir; } if (this->CTest->GetCTestConfiguration("BuildDirectory").size() > 20) { std::string bindir = this->CTest->GetCTestConfiguration("BuildDirectory") + "/"; - for (cc = bindir.size() - 2; cc > 0; cc--) { - if (bindir[cc] == '/') { - bindir = bindir.substr(0, cc + 1); - break; - } + cc = bindir.rfind('/', bindir.size() - 2); + if (cc != std::string::npos) { + bindir.resize(cc + 1); + this->SimplifyBuildDir = std::move(bindir); } - this->SimplifyBuildDir = bindir; } // Ok, let's do the build @@ -545,11 +541,11 @@ void cmCTestBuildHandler::GenerateXMLLaunched(cmXMLWriter& xml) const char* fname = launchDir.GetFile(i); if (this->IsLaunchedErrorFile(fname) && numErrorsAllowed) { numErrorsAllowed--; - fragments.insert(this->CTestLaunchDir + "/" + fname); + fragments.insert(this->CTestLaunchDir + '/' + fname); ++this->TotalErrors; } else if (this->IsLaunchedWarningFile(fname) && numWarningsAllowed) { numWarningsAllowed--; - fragments.insert(this->CTestLaunchDir + "/" + fname); + fragments.insert(this->CTestLaunchDir + '/' + fname); ++this->TotalWarnings; } } diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx index 45ec39066..1209e06d0 100644 --- a/Source/CTest/cmCTestCVS.cxx +++ b/Source/CTest/cmCTestCVS.cxx @@ -152,10 +152,12 @@ private: this->FinishRevision(); } } else if (this->Section == SectionRevisions) { + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) if (!this->Rev.Log.empty()) { // Continue the existing log. this->Rev.Log += this->Line; - this->Rev.Log += "\n"; + this->Rev.Log += '\n'; } else if (this->Rev.Rev.empty() && this->RegexRevision.find(this->Line)) { this->Rev.Rev = this->RegexRevision.match(1); @@ -166,7 +168,7 @@ private: } else if (!this->RegexBranches.find(this->Line)) { // Start the log. this->Rev.Log += this->Line; - this->Rev.Log += "\n"; + this->Rev.Log += '\n'; } } return this->Section != SectionEnd; diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx index 385471081..f42c3f18a 100644 --- a/Source/CTest/cmCTestConfigureCommand.cxx +++ b/Source/CTest/cmCTestConfigureCommand.cxx @@ -6,7 +6,7 @@ #include <sstream> #include <vector> -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmCTest.h" #include "cmCTestConfigureHandler.h" diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx index d6e6be395..7432d0850 100644 --- a/Source/CTest/cmCTestCoverageCommand.cxx +++ b/Source/CTest/cmCTestCoverageCommand.cxx @@ -4,9 +4,9 @@ #include <set> -#include "cm_static_string_view.hxx" +#include <cmext/algorithm> +#include <cmext/string_view> -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestCoverageHandler.h" @@ -22,7 +22,7 @@ void cmCTestCoverageCommand::CheckArguments( std::vector<std::string> const& keywords) { this->LabelsMentioned = - !this->Labels.empty() || cmContains(keywords, "LABELS"); + !this->Labels.empty() || cm::contains(keywords, "LABELS"); } cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler() diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 2c8f11937..b839c10ad 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -680,8 +680,9 @@ void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile* mf) // #ifdef _WIN32 # define fnc(s) cmSystemTools::LowerCase(s) +# define fnc_prefix(s, t) fnc(s.substr(0, t.size())) == fnc(t) #else -# define fnc(s) s +# define fnc_prefix(s, t) cmHasPrefix(s, t) #endif bool IsFileInDir(const std::string& infile, const std::string& indir) @@ -689,8 +690,8 @@ bool IsFileInDir(const std::string& infile, const std::string& indir) std::string file = cmSystemTools::CollapseFullPath(infile); std::string dir = cmSystemTools::CollapseFullPath(indir); - return file.size() > dir.size() && - fnc(file.substr(0, dir.size())) == fnc(dir) && file[dir.size()] == '/'; + return file.size() > dir.size() && fnc_prefix(file, dir) && + file[dir.size()] == '/'; } int cmCTestCoverageHandler::HandlePHPCoverage( @@ -1214,8 +1215,6 @@ int cmCTestCoverageHandler::HandleGCovCoverage( while (cmSystemTools::GetLineFromStream(ifile, nl)) { cnt++; - // TODO: Handle gcov 3.0 non-coverage lines - // Skip empty lines if (nl.empty()) { continue; @@ -1226,6 +1225,14 @@ int cmCTestCoverageHandler::HandleGCovCoverage( continue; } + // Handle gcov 3.0 non-coverage lines + // non-coverage lines seem to always start with something not + // a space and don't have a ':' in the 9th position + // TODO: Verify that this is actually a robust metric + if (nl[0] != ' ' && nl[9] != ':') { + continue; + } + // Read the coverage count from the beginning of the gcov output // line std::string prefix = nl.substr(0, 12); @@ -1709,29 +1716,26 @@ int cmCTestCoverageHandler::HandleTracePyCoverage( // Read the coverage count from the beginning of the Trace.py output // line - std::string prefix = nl.substr(0, 6); - if (prefix[5] != ' ' && prefix[5] != ':') { - // This is a hack. We should really do something more elaborate - prefix = nl.substr(0, 7); - if (prefix[6] != ' ' && prefix[6] != ':') { - prefix = nl.substr(0, 8); - if (prefix[7] != ' ' && prefix[7] != ':') { - cmCTestLog(this->CTest, ERROR_MESSAGE, - "Currently the limit is maximum coverage of 999999" - << std::endl); - } + std::string::size_type pos; + int cov = 0; + // This is a hack. We should really do something more elaborate + for (pos = 5; pos < 8; pos++) { + if (nl[pos] == ' ') { + // This line does not have ':' so no coverage here. That said, + // Trace.py does not handle not covered lines versus comments etc. + // So, this will be set to 0. + break; + } + if (nl[pos] == ':') { + cov = atoi(nl.substr(0, pos - 1).c_str()); + break; } } - int cov = atoi(prefix.c_str()); - if (prefix[prefix.size() - 1] != ':') { - // This line does not have ':' so no coverage here. That said, - // Trace.py does not handle not covered lines versus comments etc. - // So, this will be set to 0. - cov = 0; + if (pos == 8) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Currently the limit is maximum coverage of 999999" + << std::endl); } - cmCTestOptionalLog( - this->CTest, DEBUG, - "Prefix: " << prefix << " cov: " << cov << std::endl, this->Quiet); // Read the line number starting at the 10th character of the gcov // output line long lineIdx = cnt; diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h index 9c5ba667e..b0d7f0757 100644 --- a/Source/CTest/cmCTestCurl.h +++ b/Source/CTest/cmCTestCurl.h @@ -8,7 +8,7 @@ #include <string> #include <vector> -#include "cm_curl.h" +#include <cm3p/curl/curl.h> class cmCTest; diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index 3f3c1074f..568b0917c 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -6,6 +6,7 @@ #include <cstdio> #include <cstdlib> #include <ctime> +#include <utility> #include <vector> #include "cmsys/FStream.hxx" @@ -193,7 +194,8 @@ bool cmCTestGIT::UpdateByFetchAndReset() if (line.find("\tnot-for-merge\t") == std::string::npos) { std::string::size_type pos = line.find('\t'); if (pos != std::string::npos) { - sha1 = line.substr(0, pos); + sha1 = std::move(line); + sha1.resize(pos); } } } diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index b1034c9ff..a755632c5 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -7,7 +7,7 @@ #include <cstring> #include <sstream> -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmCTest.h" #include "cmCTestGenericHandler.h" diff --git a/Source/CTest/cmCTestMemCheckCommand.cxx b/Source/CTest/cmCTestMemCheckCommand.cxx index 39dec6d87..d0e297452 100644 --- a/Source/CTest/cmCTestMemCheckCommand.cxx +++ b/Source/CTest/cmCTestMemCheckCommand.cxx @@ -2,7 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestMemCheckCommand.h" -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmCTest.h" #include "cmCTestMemCheckHandler.h" diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index c1ecaf125..85b8ab15f 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -10,11 +10,12 @@ #include <sstream> #include <utility> +#include <cmext/algorithm> + #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmDuration.h" #include "cmSystemTools.h" @@ -297,9 +298,6 @@ void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile* mf) this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_MEMCHECK_IGNORE", this->CustomTestsIgnore); - std::string cmake = cmSystemTools::GetCMakeCommand(); - this->CTest->SetCTestConfiguration("CMakeCommand", cmake.c_str(), - this->Quiet); } int cmCTestMemCheckHandler::GetDefectCount() @@ -490,31 +488,31 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() } if (this->CTest->GetCTestConfiguration("MemoryCheckType") == "AddressSanitizer") { - this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand"); + this->MemoryTester = cmSystemTools::GetCMakeCommand(); this->MemoryTesterStyle = cmCTestMemCheckHandler::ADDRESS_SANITIZER; this->LogWithPID = true; // even if we give the log file the pid is added } if (this->CTest->GetCTestConfiguration("MemoryCheckType") == "LeakSanitizer") { - this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand"); + this->MemoryTester = cmSystemTools::GetCMakeCommand(); this->MemoryTesterStyle = cmCTestMemCheckHandler::LEAK_SANITIZER; this->LogWithPID = true; // even if we give the log file the pid is added } if (this->CTest->GetCTestConfiguration("MemoryCheckType") == "ThreadSanitizer") { - this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand"); + this->MemoryTester = cmSystemTools::GetCMakeCommand(); this->MemoryTesterStyle = cmCTestMemCheckHandler::THREAD_SANITIZER; this->LogWithPID = true; // even if we give the log file the pid is added } if (this->CTest->GetCTestConfiguration("MemoryCheckType") == "MemorySanitizer") { - this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand"); + this->MemoryTester = cmSystemTools::GetCMakeCommand(); this->MemoryTesterStyle = cmCTestMemCheckHandler::MEMORY_SANITIZER; this->LogWithPID = true; // even if we give the log file the pid is added } if (this->CTest->GetCTestConfiguration("MemoryCheckType") == "UndefinedBehaviorSanitizer") { - this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand"); + this->MemoryTester = cmSystemTools::GetCMakeCommand(); this->MemoryTesterStyle = cmCTestMemCheckHandler::UB_SANITIZER; this->LogWithPID = true; // even if we give the log file the pid is added } @@ -594,11 +592,11 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() std::string tempDrMemoryDir = this->CTest->GetBinaryDir() + "/Testing/Temporary/DrMemory"; - if (!cmContains(this->MemoryTesterOptions, "-quiet")) { + if (!cm::contains(this->MemoryTesterOptions, "-quiet")) { this->MemoryTesterOptions.emplace_back("-quiet"); } - if (!cmContains(this->MemoryTesterOptions, "-batch")) { + if (!cm::contains(this->MemoryTesterOptions, "-batch")) { this->MemoryTesterOptions.emplace_back("-batch"); } @@ -957,35 +955,25 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput( "valgrind line " << lines[cc] << std::endl, this->Quiet); int failure = cmCTestMemCheckHandler::NO_MEMORY_FAULT; - if (vgFIM.find(lines[cc])) { + auto& line = lines[cc]; + if (vgFIM.find(line)) { failure = cmCTestMemCheckHandler::FIM; - } else if (vgFMM.find(lines[cc])) { + } else if (vgFMM.find(line)) { failure = cmCTestMemCheckHandler::FMM; - } else if (vgMLK1.find(lines[cc])) { - failure = cmCTestMemCheckHandler::MLK; - } else if (vgMLK2.find(lines[cc])) { + } else if (vgMLK1.find(line) || vgMLK2.find(line)) { failure = cmCTestMemCheckHandler::MLK; - } else if (vgPAR.find(lines[cc])) { + } else if (vgPAR.find(line)) { failure = cmCTestMemCheckHandler::PAR; - } else if (vgMPK1.find(lines[cc])) { - failure = cmCTestMemCheckHandler::MPK; - } else if (vgMPK2.find(lines[cc])) { + } else if (vgMPK1.find(line) || vgMPK2.find(line)) { failure = cmCTestMemCheckHandler::MPK; - } else if (vgUMC.find(lines[cc])) { + } else if (vgUMC.find(line)) { failure = cmCTestMemCheckHandler::UMC; - } else if (vgUMR1.find(lines[cc])) { - failure = cmCTestMemCheckHandler::UMR; - } else if (vgUMR2.find(lines[cc])) { - failure = cmCTestMemCheckHandler::UMR; - } else if (vgUMR3.find(lines[cc])) { + } else if (vgUMR1.find(line) || vgUMR2.find(line) || vgUMR3.find(line) || + vgUMR4.find(line) || vgUMR5.find(line)) { failure = cmCTestMemCheckHandler::UMR; - } else if (vgUMR4.find(lines[cc])) { - failure = cmCTestMemCheckHandler::UMR; - } else if (vgUMR5.find(lines[cc])) { - failure = cmCTestMemCheckHandler::UMR; - } else if (vgIPW.find(lines[cc])) { + } else if (vgIPW.find(line)) { failure = cmCTestMemCheckHandler::IPW; - } else if (vgABR.find(lines[cc])) { + } else if (vgABR.find(line)) { failure = cmCTestMemCheckHandler::ABR; } @@ -1049,13 +1037,9 @@ bool cmCTestMemCheckHandler::ProcessMemCheckDrMemoryOutput( ostr << l << std::endl; if (drMemoryError.find(l)) { defects++; - if (unaddressableAccess.find(l)) { + if (unaddressableAccess.find(l) || uninitializedRead.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)) { + } else if (leak.find(l) || handleLeak.find(l)) { results[cmCTestMemCheckHandler::MLK]++; } else if (invalidHeapArgument.find(l)) { results[cmCTestMemCheckHandler::FMM]++; diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 2192843ec..a08cb3480 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -6,30 +6,29 @@ #include <cassert> #include <chrono> #include <cmath> -#include <cstddef> +#include <cstddef> // IWYU pragma: keep #include <cstdlib> #include <cstring> #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 <cm3p/json/value.h> +#include <cm3p/json/writer.h> +#include <cm3p/uv.h> + #include "cmsys/FStream.hxx" #include "cmsys/SystemInformation.hxx" -#include "cm_jsoncpp_value.h" -#include "cm_jsoncpp_writer.h" -#include "cm_uv.h" - #include "cmAffinity.h" -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestBinPacker.h" #include "cmCTestRunTest.h" @@ -138,7 +137,7 @@ void cmCTestMultiProcessHandler::RunTests() uv_run(&this->Loop, UV_RUN_DEFAULT); uv_loop_close(&this->Loop); - if (!this->StopTimePassed) { + if (!this->StopTimePassed && !this->CheckStopOnFailure()) { assert(this->Completed == this->Total); assert(this->Tests.empty()); } @@ -172,7 +171,8 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) this->EraseTest(test); this->RunningCount += GetProcessorsUsed(test); - cmCTestRunTest* testRun = new cmCTestRunTest(*this); + auto testRun = cm::make_unique<cmCTestRunTest>(*this); + if (this->RepeatMode != cmCTest::Repeat::Never) { testRun->SetRepeatMode(this->RepeatMode); testRun->SetNumberOfRuns(this->RepeatCount); @@ -187,7 +187,7 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) // Find any failed dependencies for this test. We assume the more common // scenario has no failed tests, so make it the outer loop. for (std::string const& f : *this->Failed) { - if (cmContains(this->Properties[test]->RequireSuccessDepends, f)) { + if (cm::contains(this->Properties[test]->RequireSuccessDepends, f)) { testRun->AddFailedDependency(f); } } @@ -229,28 +229,25 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) e << "\n"; } e << "Resource spec file:\n\n " << this->TestHandler->ResourceSpecFile; - testRun->StartFailure(e.str(), "Insufficient resources"); - this->FinishTestProcess(testRun, false); + 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()), - "Failed to change working directory"); - } 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) @@ -370,6 +367,11 @@ void cmCTestMultiProcessHandler::CheckResourcesAvailable() } } +bool cmCTestMultiProcessHandler::CheckStopOnFailure() +{ + return this->CTest->GetStopOnFailure(); +} + bool cmCTestMultiProcessHandler::CheckStopTimePassed() { if (!this->StopTimePassed) { @@ -447,7 +449,7 @@ bool cmCTestMultiProcessHandler::StartTest(int test) { // Check for locked resources for (std::string const& i : this->Properties[test]->LockedResources) { - if (cmContains(this->LockedResources, i)) { + if (cm::contains(this->LockedResources, i)) { return false; } } @@ -486,6 +488,10 @@ void cmCTestMultiProcessHandler::StartNextTests() return; } + if (this->CheckStopOnFailure() && !this->Failed->empty()) { + return; + } + size_t numToStart = 0; if (this->RunningCount < this->ParallelLevel) { @@ -540,7 +546,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; } @@ -618,8 +625,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++; @@ -631,7 +638,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; } @@ -659,7 +667,7 @@ void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner, } properties->Affinity.clear(); - delete runner; + runner.reset(); if (started) { this->StartNextTests(); } @@ -802,7 +810,7 @@ void cmCTestMultiProcessHandler::CreateParallelTestCostList() // In parallel test runs add previously failed tests to the front // of the cost list and queue other tests for further sorting for (auto const& t : this->Tests) { - if (cmContains(this->LastTestsFailed, this->Properties[t.first]->Name)) { + if (cm::contains(this->LastTestsFailed, this->Properties[t.first]->Name)) { // If the test failed last time, it should be run first. this->SortedTests.push_back(t.first); alreadySortedTests.insert(t.first); @@ -841,7 +849,7 @@ void cmCTestMultiProcessHandler::CreateParallelTestCostList() TestComparator(this)); for (auto const& j : sortedCopy) { - if (!cmContains(alreadySortedTests, j)) { + if (!cm::contains(alreadySortedTests, j)) { this->SortedTests.push_back(j); alreadySortedTests.insert(j); } @@ -873,7 +881,7 @@ void cmCTestMultiProcessHandler::CreateSerialTestCostList() TestSet alreadySortedTests; for (int test : presortedList) { - if (cmContains(alreadySortedTests, test)) { + if (cm::contains(alreadySortedTests, test)) { continue; } @@ -881,7 +889,7 @@ void cmCTestMultiProcessHandler::CreateSerialTestCostList() GetAllTestDependencies(test, dependencies); for (int testDependency : dependencies) { - if (!cmContains(alreadySortedTests, testDependency)) { + if (!cm::contains(alreadySortedTests, testDependency)) { alreadySortedTests.insert(testDependency); this->SortedTests.push_back(testDependency); } diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index 5b429d4ae..e21b912c7 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -6,14 +6,14 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <map> +#include <memory> #include <set> #include <string> #include <vector> +#include <cm3p/uv.h> #include <stddef.h> -#include "cm_uv.h" - #include "cmCTest.h" #include "cmCTestResourceAllocator.h" #include "cmCTestTestHandler.h" @@ -124,7 +124,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,6 +137,8 @@ protected: inline size_t GetProcessorsUsed(int index); std::string GetName(int index); + bool CheckStopOnFailure(); + bool CheckStopTimePassed(); void SetStopTimePassed(); diff --git a/Source/CTest/cmCTestResourceSpec.cxx b/Source/CTest/cmCTestResourceSpec.cxx index 8f91efb45..21c97de34 100644 --- a/Source/CTest/cmCTestResourceSpec.cxx +++ b/Source/CTest/cmCTestResourceSpec.cxx @@ -7,12 +7,12 @@ #include <utility> #include <vector> +#include <cm3p/json/reader.h> +#include <cm3p/json/value.h> + #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" -#include "cm_jsoncpp_reader.h" -#include "cm_jsoncpp_value.h" - static const cmsys::RegularExpression IdentifierRegex{ "^[a-z_][a-z0-9_]*$" }; static const cmsys::RegularExpression IdRegex{ "^[a-z0-9_]+$" }; diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 58289ea50..2c8e3855f 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -3,7 +3,7 @@ #include "cmCTestRunTest.h" #include <chrono> -#include <cstddef> +#include <cstddef> // IWYU pragma: keep #include <cstdint> #include <cstdio> #include <cstring> @@ -314,23 +314,27 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) 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()), - "Failed to change working directory"); + 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; } @@ -387,6 +391,18 @@ void cmCTestRunTest::MemCheckPostProcess() handler->PostProcessTest(this->TestResult, this->Index); } +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) { @@ -418,7 +434,7 @@ void cmCTestRunTest::StartFailure(std::string const& output, this->TestResult.Path = this->TestProperties->Directory; this->TestResult.Output = output; this->TestResult.FullCommandLine.clear(); - this->TestProcess = cm::make_unique<cmProcess>(*this); + this->TestResult.Environment.clear(); } std::string cmCTestRunTest::GetTestPrefix(size_t completed, size_t total) const @@ -442,6 +458,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) { @@ -473,9 +504,9 @@ 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(); + this->TestResult.Environment.clear(); return false; } @@ -487,7 +518,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,6 +526,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total) cmCTestLog(this->CTest, HANDLER_OUTPUT, msg << std::endl); this->TestResult.Output = msg; this->TestResult.FullCommandLine.clear(); + this->TestResult.Environment.clear(); this->TestResult.CompletionStatus = "Fixture dependency failed"; this->TestResult.Status = cmCTestTestHandler::NOT_RUN; return false; @@ -504,7 +535,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 " @@ -517,6 +547,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total) cmCTestLog(this->CTest, ERROR_MESSAGE, msg << std::endl); this->TestResult.Output = msg; this->TestResult.FullCommandLine.clear(); + this->TestResult.Environment.clear(); this->TestResult.CompletionStatus = "Missing Configuration"; this->TestResult.Status = cmCTestTestHandler::NOT_RUN; return false; @@ -526,13 +557,13 @@ 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, "Unable to find required file: " << file << std::endl); this->TestResult.Output = "Unable to find required file: " + file; this->TestResult.FullCommandLine.clear(); + this->TestResult.Environment.clear(); this->TestResult.CompletionStatus = "Required Files Missing"; this->TestResult.Status = cmCTestTestHandler::NOT_RUN; return false; @@ -542,13 +573,13 @@ 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, "Unable to find executable: " << args[1] << std::endl); this->TestResult.Output = "Unable to find executable: " + args[1]; this->TestResult.FullCommandLine.clear(); + this->TestResult.Environment.clear(); this->TestResult.CompletionStatus = "Unable to find executable"; this->TestResult.Status = cmCTestTestHandler::NOT_RUN; return false; @@ -654,7 +685,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); @@ -694,25 +724,43 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, cmSystemTools::SaveRestoreEnvironment sre; #endif + std::ostringstream envMeasurement; if (environment && !environment->empty()) { cmSystemTools::AppendEnv(*environment); + for (auto const& var : *environment) { + envMeasurement << var << std::endl; + } } if (this->UseAllocatedResources) { - this->SetupResourcesEnvironment(); + std::vector<std::string> envLog; + this->SetupResourcesEnvironment(&envLog); + for (auto const& var : envLog) { + envMeasurement << var << std::endl; + } } else { cmSystemTools::UnsetEnv("CTEST_RESOURCE_GROUP_COUNT"); + // Signify that this variable is being actively unset + envMeasurement << "#CTEST_RESOURCE_GROUP_COUNT=" << std::endl; } + this->TestResult.Environment = envMeasurement.str(); + // Remove last newline + this->TestResult.Environment.erase(this->TestResult.Environment.length() - + 1); + return this->TestProcess->StartProcess(this->MultiTestHandler.Loop, affinity); } -void cmCTestRunTest::SetupResourcesEnvironment() +void cmCTestRunTest::SetupResourcesEnvironment(std::vector<std::string>* log) { std::string processCount = "CTEST_RESOURCE_GROUP_COUNT="; processCount += std::to_string(this->AllocatedResources.size()); cmSystemTools::PutEnv(processCount); + if (log) { + log->push_back(processCount); + } std::size_t i = 0; for (auto const& process : this->AllocatedResources) { @@ -738,8 +786,14 @@ void cmCTestRunTest::SetupResourcesEnvironment() var += "id:" + it2.Id + ",slots:" + std::to_string(it2.Slots); } cmSystemTools::PutEnv(var); + if (log) { + log->push_back(var); + } } cmSystemTools::PutEnv(resourceList); + if (log) { + log->push_back(resourceList); + } ++i; } } @@ -821,7 +875,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 4988839b0..d831247e1 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -65,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 @@ -74,8 +83,6 @@ public: void ComputeWeightedCost(); - bool StartAgain(size_t completed); - void StartFailure(std::string const& output, std::string const& detail); cmCTest* GetCTest() const { return this->CTest; } @@ -84,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; } @@ -112,7 +119,7 @@ private: // Run post processing of the process output for MemCheck void MemCheckPostProcess(); - void SetupResourcesEnvironment(); + void SetupResourcesEnvironment(std::vector<std::string>* log = nullptr); // Returns "completed/total Test #Index: " std::string GetTestPrefix(size_t completed, size_t total) const; diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 7803e3764..4fa4dc0da 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()); @@ -310,12 +284,14 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg) // if the argument has a , in it then it needs to be broken into the fist // argument (which is the script) and the second argument which will be // passed into the scripts as S_ARG - std::string script = total_script_arg; + std::string script; std::string script_arg; const std::string::size_type comma_pos = total_script_arg.find(','); if (comma_pos != std::string::npos) { script = total_script_arg.substr(0, comma_pos); script_arg = total_script_arg.substr(comma_pos + 1); + } else { + script = total_script_arg; } // make sure the file exists if (!cmSystemTools::FileExists(script)) { @@ -878,7 +854,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); @@ -886,7 +862,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 d0031990b..ebb79055f 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 acb75b2ed..279216eeb 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -8,10 +8,9 @@ #include <cm/memory> #include <cm/vector> +#include <cmext/algorithm> +#include <cmext/string_view> -#include "cm_static_string_view.hxx" - -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestSubmitHandler.h" #include "cmCommand.h" @@ -172,8 +171,10 @@ void cmCTestSubmitCommand::BindArguments() void cmCTestSubmitCommand::CheckArguments( std::vector<std::string> const& keywords) { - this->PartsMentioned = !this->Parts.empty() || cmContains(keywords, "PARTS"); - this->FilesMentioned = !this->Files.empty() || cmContains(keywords, "FILES"); + this->PartsMentioned = + !this->Parts.empty() || cm::contains(keywords, "PARTS"); + this->FilesMentioned = + !this->Files.empty() || cm::contains(keywords, "FILES"); cm::erase_if(this->Parts, [this](std::string const& arg) -> bool { cmCTest::Part p = this->CTest->GetPartFromName(arg.c_str()); diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 22ab48f57..ea36df54a 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -9,9 +9,9 @@ #include <cmext/algorithm> -#include "cm_curl.h" -#include "cm_jsoncpp_reader.h" -#include "cm_jsoncpp_value.h" +#include <cm3p/curl/curl.h> +#include <cm3p/json/reader.h> +#include <cm3p/json/value.h> #include "cmAlgorithms.h" #include "cmCTest.h" @@ -21,6 +21,7 @@ #include "cmCurl.h" #include "cmDuration.h" #include "cmGeneratedFileStream.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -260,11 +261,10 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP( cmCTestScriptHandler* ch = this->CTest->GetScriptHandler(); cmake* cm = ch->GetCMake(); if (cm) { - const char* subproject = - cm->GetState()->GetGlobalProperty("SubProject"); + cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject"); if (subproject) { upload_as += "&subproject="; - upload_as += ctest_curl.Escape(subproject); + upload_as += ctest_curl.Escape(*subproject); } } } @@ -506,18 +506,19 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, curl.SetTimeOutSeconds(SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT); curl.SetHttpHeaders(this->HttpHeaders); std::string url = this->CTest->GetSubmitURL(); - std::string fields; - std::string::size_type pos = url.find('?'); - if (pos != std::string::npos) { - fields = url.substr(pos + 1); - url = url.substr(0, pos); - } if (!cmHasLiteralPrefix(url, "http://") && !cmHasLiteralPrefix(url, "https://")) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Only http and https are supported for CDASH_UPLOAD\n"); return -1; } + + std::string fields; + std::string::size_type pos = url.find('?'); + if (pos != std::string::npos) { + fields = url.substr(pos + 1); + url.erase(pos); + } bool internalTest = cmIsOn(this->GetOption("InternalTest")); // Get RETRY_COUNT and RETRY_DELAY values if they were set. @@ -555,11 +556,11 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, // a "&subproject=subprojectname" to the first POST. cmCTestScriptHandler* ch = this->CTest->GetScriptHandler(); cmake* cm = ch->GetCMake(); - const char* subproject = cm->GetState()->GetGlobalProperty("SubProject"); + cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject"); // TODO: Encode values for a URL instead of trusting caller. std::ostringstream str; if (subproject) { - str << "subproject=" << curl.Escape(subproject) << "&"; + str << "subproject=" << curl.Escape(*subproject) << "&"; } auto timeNow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx index 0f9b6958d..c71b409ff 100644 --- a/Source/CTest/cmCTestTestCommand.cxx +++ b/Source/CTest/cmCTestTestCommand.cxx @@ -6,7 +6,7 @@ #include <cstdlib> #include <sstream> -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmCTest.h" #include "cmCTestGenericHandler.h" @@ -34,6 +34,7 @@ void cmCTestTestCommand::BindArguments() this->Bind("STOP_TIME"_s, this->StopTime); this->Bind("TEST_LOAD"_s, this->TestLoad); this->Bind("RESOURCE_SPEC_FILE"_s, this->ResourceSpecFile); + this->Bind("STOP_ON_FAILURE"_s, this->StopOnFailure); } cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() @@ -52,6 +53,13 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() } } this->CTest->SetTimeOut(timeout); + + const char* resourceSpecFile = + this->Makefile->GetDefinition("CTEST_RESOURCE_SPEC_FILE"); + if (this->ResourceSpecFile.empty() && resourceSpecFile) { + this->ResourceSpecFile = resourceSpecFile; + } + cmCTestGenericHandler* handler = this->InitializeActualHandler(); if (!this->Start.empty() || !this->End.empty() || !this->Stride.empty()) { handler->SetOption( @@ -83,6 +91,9 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() handler->SetOption("ExcludeFixtureCleanupRegularExpression", this->ExcludeFixtureCleanup.c_str()); } + if (this->StopOnFailure) { + handler->SetOption("StopOnFailure", "ON"); + } if (!this->ParallelLevel.empty()) { handler->SetOption("ParallelLevel", this->ParallelLevel.c_str()); } diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h index 2345afbcf..792558679 100644 --- a/Source/CTest/cmCTestTestCommand.h +++ b/Source/CTest/cmCTestTestCommand.h @@ -60,6 +60,7 @@ protected: std::string StopTime; std::string TestLoad; std::string ResourceSpecFile; + bool StopOnFailure = false; }; #endif diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 4f324ea6d..d0dbaae81 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -5,7 +5,7 @@ #include <algorithm> #include <chrono> #include <cmath> -#include <cstddef> +#include <cstddef> // IWYU pragma: keep #include <cstdio> #include <cstdlib> #include <cstring> @@ -18,6 +18,9 @@ #include <utility> #include <cm/memory> +#include <cm/string_view> +#include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/FStream.hxx" #include <cmsys/Base64.h> @@ -26,7 +29,6 @@ #include "cm_utf8.h" -#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestMultiProcessHandler.h" #include "cmCTestResourceGroupsLexerHelper.h" @@ -406,7 +408,9 @@ int cmCTestTestHandler::ProcessHandler() // start the real time clock auto clock_start = std::chrono::steady_clock::now(); - this->ProcessDirectory(passed, failed); + if (!this->ProcessDirectory(passed, failed)) { + return -1; + } auto clock_finish = std::chrono::steady_clock::now(); @@ -510,6 +514,10 @@ bool cmCTestTestHandler::ProcessOptions() this->CTest->SetParallelLevel(atoi(this->GetOption("ParallelLevel"))); } + if (this->GetOption("StopOnFailure")) { + this->CTest->SetStopOnFailure(true); + } + const char* val; val = this->GetOption("LabelRegularExpression"); if (val) { @@ -543,22 +551,11 @@ bool cmCTestTestHandler::ProcessOptions() if (val) { this->ExcludeFixtureCleanupRegExp = val; } - this->SetRerunFailed(cmIsOn(this->GetOption("RerunFailed"))); - 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, - "Could not read/parse resource spec file " - << val << ": " - << cmCTestResourceSpec::ResultToString(result) - << std::endl); - return false; - } } + this->SetRerunFailed(cmIsOn(this->GetOption("RerunFailed"))); return true; } @@ -718,7 +715,7 @@ void cmCTestTestHandler::PrintLabelOrSubprojectSummary(bool doSubProject) cmCTestTestProperties& p = *result.Properties; for (std::string const& l : p.Labels) { // only use labels found in labels - if (cmContains(labels, l)) { + if (cm::contains(labels, l)) { labelTimes[l] += result.ExecutionTime.count() * result.Properties->Processors; ++labelCounts[l]; @@ -860,14 +857,15 @@ void cmCTestTestHandler::ComputeTestList() if (this->UseUnion) { // if it is not in the list and not in the regexp then skip - if ((!this->TestsToRun.empty() && !cmContains(this->TestsToRun, cnt)) && + if ((!this->TestsToRun.empty() && + !cm::contains(this->TestsToRun, cnt)) && !tp.IsInBasedOnREOptions) { continue; } } else { // is this test in the list of tests to run? If not then skip it if ((!this->TestsToRun.empty() && - !cmContains(this->TestsToRun, inREcnt)) || + !cm::contains(this->TestsToRun, inREcnt)) || !tp.IsInBasedOnREOptions) { continue; } @@ -896,7 +894,7 @@ void cmCTestTestHandler::ComputeTestListForRerunFailed() cnt++; // if this test is not in our list of tests to run, then skip it. - if (!this->TestsToRun.empty() && !cmContains(this->TestsToRun, cnt)) { + if (!this->TestsToRun.empty() && !cm::contains(this->TestsToRun, cnt)) { continue; } @@ -1015,7 +1013,7 @@ void cmCTestTestHandler::UpdateForFixtures(ListOfTests& tests) const for (auto sIt = setupRange.first; sIt != setupRange.second; ++sIt) { const std::string& setupTestName = sIt->second->Name; tests[i].RequireSuccessDepends.insert(setupTestName); - if (!cmContains(tests[i].Depends, setupTestName)) { + if (!cm::contains(tests[i].Depends, setupTestName)) { tests[i].Depends.push_back(setupTestName); } } @@ -1119,7 +1117,7 @@ void cmCTestTestHandler::UpdateForFixtures(ListOfTests& tests) const const std::vector<size_t>& indices = cIt->second; for (size_t index : indices) { const std::string& reqTestName = tests[index].Name; - if (!cmContains(p.Depends, reqTestName)) { + if (!cm::contains(p.Depends, reqTestName)) { p.Depends.push_back(reqTestName); } } @@ -1132,7 +1130,7 @@ void cmCTestTestHandler::UpdateForFixtures(ListOfTests& tests) const const std::vector<size_t>& indices = cIt->second; for (size_t index : indices) { const std::string& setupTestName = tests[index].Name; - if (!cmContains(p.Depends, setupTestName)) { + if (!cm::contains(p.Depends, setupTestName)) { p.Depends.push_back(setupTestName); } } @@ -1259,7 +1257,7 @@ bool cmCTestTestHandler::GetValue(const char* tag, std::string& value, return ret; } -void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed, +bool cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed, std::vector<std::string>& failed) { this->ComputeTestList(); @@ -1267,7 +1265,7 @@ 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); @@ -1283,7 +1281,17 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed, } else { parallel->SetTestLoad(this->CTest->GetTestLoad()); } - if (this->UseResourceSpec) { + if (!this->ResourceSpecFile.empty()) { + this->UseResourceSpec = true; + auto result = this->ResourceSpec.ReadFromJSONFile(this->ResourceSpecFile); + if (result != cmCTestResourceSpec::ReadFileResult::READ_OK) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Could not read/parse resource spec file " + << this->ResourceSpecFile << ": " + << cmCTestResourceSpec::ResultToString(result) + << std::endl); + return false; + } parallel->InitResourceAllocator(this->ResourceSpec); } @@ -1338,12 +1346,13 @@ 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 = std::chrono::steady_clock::now() - elapsed_time_start; *this->LogFile << "End testing: " << this->CTest->CurrentTime() << std::endl; + + return true; } void cmCTestTestHandler::GenerateTestCommand( @@ -1423,6 +1432,12 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml) xml.Attribute("name", "Command Line"); xml.Element("Value", result.FullCommandLine); xml.EndElement(); // NamedMeasurement + + xml.StartElement("NamedMeasurement"); + xml.Attribute("type", "text/string"); + xml.Attribute("name", "Environment"); + xml.Element("Value", result.Environment); + xml.EndElement(); // NamedMeasurement for (auto const& measure : result.Properties->Measurements) { xml.StartElement("NamedMeasurement"); xml.Attribute("type", "text/string"); @@ -1742,6 +1757,10 @@ void cmCTestTestHandler::GetListOfTests() if (cmSystemTools::GetErrorOccuredFlag()) { return; } + const char* specFile = mf.GetDefinition("CTEST_RESOURCE_SPEC_FILE"); + if (this->ResourceSpecFile.empty() && specFile) { + this->ResourceSpecFile = specFile; + } cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Done constructing a list of tests" << std::endl, this->Quiet); @@ -1894,7 +1913,8 @@ void cmCTestTestHandler::ExpandTestsToRunInformationForRerunFailed() continue; } - int val = atoi(line.substr(0, pos).c_str()); + line.erase(pos); + int val = atoi(line.c_str()); this->TestsToRun.push_back(val); } ifs.close(); @@ -2016,13 +2036,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(), @@ -2039,8 +2059,6 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, } xml.Element("Value", ostr.str()); xml.EndElement(); // NamedMeasurement - delete[] file_buffer; - delete[] encoded_buffer; } } else { int idx = 4; @@ -2085,19 +2103,18 @@ 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(); } } -bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length) +void cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length) { if (!length || length >= output.size() || output.find("CTEST_FULL_OUTPUT") != std::string::npos) { - return true; + return; } // Truncate at given length but do not break in the middle of a multi-byte @@ -2118,7 +2135,7 @@ bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length) ++current; } } - output = output.substr(0, current - begin); + output.erase(current - begin); // Append truncation message. std::ostringstream msg; @@ -2128,7 +2145,6 @@ bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length) "of " << length << " bytes.\n"; output += msg.str(); - return true; } bool cmCTestTestHandler::SetTestsProperties( @@ -2149,16 +2165,16 @@ bool cmCTestTestHandler::SetTestsProperties( } ++it; // skip PROPERTIES for (; it != args.end(); ++it) { - std::string key = *it; + std::string const& key = *it; ++it; if (it == args.end()) { break; } - std::string val = *it; + std::string const& val = *it; for (std::string const& t : tests) { for (cmCTestTestProperties& rt : this->TestList) { if (t == rt.Name) { - if (key == "_BACKTRACE_TRIPLES") { + if (key == "_BACKTRACE_TRIPLES"_s) { std::vector<std::string> triples; // allow empty args in the triples cmExpandList(val, triples, true); @@ -2182,91 +2198,70 @@ bool cmCTestTestHandler::SetTestsProperties( rt.Backtrace = rt.Backtrace.Push(fc); } } - } - if (key == "WILL_FAIL") { + } else if (key == "WILL_FAIL"_s) { rt.WillFail = cmIsOn(val); - } - if (key == "DISABLED") { + } else if (key == "DISABLED"_s) { rt.Disabled = cmIsOn(val); - } - if (key == "ATTACHED_FILES") { + } else if (key == "ATTACHED_FILES"_s) { cmExpandList(val, rt.AttachedFiles); - } - if (key == "ATTACHED_FILES_ON_FAIL") { + } else if (key == "ATTACHED_FILES_ON_FAIL"_s) { cmExpandList(val, rt.AttachOnFail); - } - if (key == "RESOURCE_LOCK") { + } else if (key == "RESOURCE_LOCK"_s) { std::vector<std::string> lval = cmExpandedList(val); rt.LockedResources.insert(lval.begin(), lval.end()); - } - if (key == "FIXTURES_SETUP") { + } else if (key == "FIXTURES_SETUP"_s) { std::vector<std::string> lval = cmExpandedList(val); rt.FixturesSetup.insert(lval.begin(), lval.end()); - } - if (key == "FIXTURES_CLEANUP") { + } else if (key == "FIXTURES_CLEANUP"_s) { std::vector<std::string> lval = cmExpandedList(val); rt.FixturesCleanup.insert(lval.begin(), lval.end()); - } - if (key == "FIXTURES_REQUIRED") { + } else if (key == "FIXTURES_REQUIRED"_s) { std::vector<std::string> lval = cmExpandedList(val); rt.FixturesRequired.insert(lval.begin(), lval.end()); - } - if (key == "TIMEOUT") { + } else if (key == "TIMEOUT"_s) { rt.Timeout = cmDuration(atof(val.c_str())); rt.ExplicitTimeout = true; - } - if (key == "COST") { + } else if (key == "COST"_s) { rt.Cost = static_cast<float>(atof(val.c_str())); - } - if (key == "REQUIRED_FILES") { + } else if (key == "REQUIRED_FILES"_s) { cmExpandList(val, rt.RequiredFiles); - } - if (key == "RUN_SERIAL") { + } else if (key == "RUN_SERIAL"_s) { rt.RunSerial = cmIsOn(val); - } - if (key == "FAIL_REGULAR_EXPRESSION") { + } else if (key == "FAIL_REGULAR_EXPRESSION"_s) { std::vector<std::string> lval = cmExpandedList(val); for (std::string const& cr : lval) { rt.ErrorRegularExpressions.emplace_back(cr, cr); } - } - if (key == "SKIP_REGULAR_EXPRESSION") { + } else if (key == "SKIP_REGULAR_EXPRESSION"_s) { std::vector<std::string> lval = cmExpandedList(val); for (std::string const& cr : lval) { rt.SkipRegularExpressions.emplace_back(cr, cr); } - } - if (key == "PROCESSORS") { + } else if (key == "PROCESSORS"_s) { rt.Processors = atoi(val.c_str()); if (rt.Processors < 1) { rt.Processors = 1; } - } - if (key == "PROCESSOR_AFFINITY") { + } else if (key == "PROCESSOR_AFFINITY"_s) { rt.WantAffinity = cmIsOn(val); - } - if (key == "RESOURCE_GROUPS") { + } else if (key == "RESOURCE_GROUPS"_s) { if (!ParseResourceGroupsProperty(val, rt.ResourceGroups)) { return false; } - } - if (key == "SKIP_RETURN_CODE") { + } else if (key == "SKIP_RETURN_CODE"_s) { rt.SkipReturnCode = atoi(val.c_str()); if (rt.SkipReturnCode < 0 || rt.SkipReturnCode > 255) { rt.SkipReturnCode = -1; } - } - if (key == "DEPENDS") { + } else if (key == "DEPENDS"_s) { cmExpandList(val, rt.Depends); - } - if (key == "ENVIRONMENT") { + } else if (key == "ENVIRONMENT"_s) { cmExpandList(val, rt.Environment); - } - if (key == "LABELS") { + } else if (key == "LABELS"_s) { std::vector<std::string> Labels = cmExpandedList(val); rt.Labels.insert(rt.Labels.end(), Labels.begin(), Labels.end()); // sort the array @@ -2274,8 +2269,7 @@ bool cmCTestTestHandler::SetTestsProperties( // remove duplicates auto new_end = std::unique(rt.Labels.begin(), rt.Labels.end()); rt.Labels.erase(new_end, rt.Labels.end()); - } - if (key == "MEASUREMENT") { + } else if (key == "MEASUREMENT"_s) { size_t pos = val.find_first_of('='); if (pos != std::string::npos) { std::string mKey = val.substr(0, pos); @@ -2284,17 +2278,14 @@ bool cmCTestTestHandler::SetTestsProperties( } else { rt.Measurements[val] = "1"; } - } - if (key == "PASS_REGULAR_EXPRESSION") { + } else if (key == "PASS_REGULAR_EXPRESSION"_s) { std::vector<std::string> lval = cmExpandedList(val); for (std::string const& cr : lval) { rt.RequiredRegularExpressions.emplace_back(cr, cr); } - } - if (key == "WORKING_DIRECTORY") { + } else if (key == "WORKING_DIRECTORY"_s) { rt.Directory = val; - } - if (key == "TIMEOUT_AFTER_MATCH") { + } else if (key == "TIMEOUT_AFTER_MATCH"_s) { std::vector<std::string> propArgs = cmExpandedList(val); if (propArgs.size() != 2) { cmCTestLog(this->CTest, WARNING, @@ -2334,16 +2325,16 @@ bool cmCTestTestHandler::SetDirectoryProperties( } ++it; // skip PROPERTIES for (; it != args.end(); ++it) { - std::string key = *it; + std::string const& key = *it; ++it; if (it == args.end()) { break; } - std::string val = *it; + std::string const& val = *it; for (cmCTestTestProperties& rt : this->TestList) { std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); if (cwd == rt.Directory) { - if (key == "LABELS") { + if (key == "LABELS"_s) { std::vector<std::string> DirectoryLabels = cmExpandedList(val); rt.Labels.insert(rt.Labels.end(), DirectoryLabels.begin(), DirectoryLabels.end()); @@ -2422,10 +2413,9 @@ bool cmCTestTestHandler::AddTest(const std::vector<std::string>& args) test.SkipReturnCode = -1; test.PreviousRuns = 0; if (this->UseIncludeRegExpFlag && - !this->IncludeTestsRegularExpression.find(testname)) { - test.IsInBasedOnREOptions = false; - } else if (this->UseExcludeRegExpFlag && !this->UseExcludeRegExpFirst && - this->ExcludeTestsRegularExpression.find(testname)) { + (!this->IncludeTestsRegularExpression.find(testname) || + (!this->UseExcludeRegExpFirst && + this->ExcludeTestsRegularExpression.find(testname)))) { test.IsInBasedOnREOptions = false; } this->TestList.push_back(test); diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index b1c875502..0d88c306f 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -169,6 +169,7 @@ public: std::string Path; std::string Reason; std::string FullCommandLine; + std::string Environment; cmDuration ExecutionTime; std::int64_t ReturnValue; int Status; @@ -235,7 +236,7 @@ protected: void AttachFiles(cmXMLWriter& xml, cmCTestTestResult& result); //! Clean test output to specified length - bool CleanTestOutput(std::string& output, size_t length); + void CleanTestOutput(std::string& output, size_t length); cmDuration ElapsedTestingTime; @@ -278,7 +279,7 @@ private: /** * Run the tests for a directory and any subdirectories */ - void ProcessDirectory(std::vector<std::string>& passed, + bool ProcessDirectory(std::vector<std::string>& passed, std::vector<std::string>& failed); /** diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx index eaef1ca6a..f86ee0d7c 100644 --- a/Source/CTest/cmCTestUploadCommand.cxx +++ b/Source/CTest/cmCTestUploadCommand.cxx @@ -6,8 +6,7 @@ #include <sstream> #include <cm/vector> - -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmCTest.h" #include "cmCTestUploadHandler.h" diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx index 6026c69bb..452d7143b 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 2a4765d28..3037e01c9 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/cmParseCacheCoverage.cxx b/Source/CTest/cmParseCacheCoverage.cxx index 8c4da7577..84d7de02c 100644 --- a/Source/CTest/cmParseCacheCoverage.cxx +++ b/Source/CTest/cmParseCacheCoverage.cxx @@ -4,6 +4,7 @@ #include <cstdlib> #include <map> #include <utility> +#include <vector> #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" @@ -19,7 +20,7 @@ cmParseCacheCoverage::cmParseCacheCoverage( { } -bool cmParseCacheCoverage::LoadCoverageData(const char* d) +bool cmParseCacheCoverage::LoadCoverageData(std::string const& d) { // load all the .mcov files in the specified directory cmsys::Directory dir; @@ -69,26 +70,6 @@ void cmParseCacheCoverage::RemoveUnCoveredFiles() } } -bool cmParseCacheCoverage::SplitString(std::vector<std::string>& args, - std::string const& line) -{ - std::string::size_type pos1 = 0; - std::string::size_type pos2 = line.find(',', 0); - if (pos2 == std::string::npos) { - return false; - } - std::string arg; - while (pos2 != std::string::npos) { - arg = line.substr(pos1, pos2 - pos1); - args.push_back(arg); - pos1 = pos2 + 1; - pos2 = line.find(',', pos1); - } - arg = line.substr(pos1); - args.push_back(arg); - return true; -} - bool cmParseCacheCoverage::ReadCMCovFile(const char* file) { cmsys::ifstream in(file); @@ -97,7 +78,6 @@ bool cmParseCacheCoverage::ReadCMCovFile(const char* file) return false; } std::string line; - std::vector<std::string> separateLine; if (!cmSystemTools::GetLineFromStream(in, line)) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Empty file : " << file @@ -106,8 +86,8 @@ bool cmParseCacheCoverage::ReadCMCovFile(const char* file) << line << "]\n"); return false; } - separateLine.clear(); - this->SplitString(separateLine, line); + std::vector<std::string> separateLine = + cmSystemTools::SplitString(line, ','); if (separateLine.size() != 4 || separateLine[0] != "Routine" || separateLine[1] != "Line" || separateLine[2] != "RtnLine" || separateLine[3] != "Code") { @@ -120,10 +100,8 @@ bool cmParseCacheCoverage::ReadCMCovFile(const char* file) std::string routine; std::string filepath; while (cmSystemTools::GetLineFromStream(in, line)) { - // clear out line argument vector - separateLine.clear(); // parse the comma separated line - this->SplitString(separateLine, line); + separateLine = cmSystemTools::SplitString(line, ','); // might have more because code could have a quoted , in it // but we only care about the first 3 args anyway if (separateLine.size() < 4) { @@ -155,7 +133,7 @@ bool cmParseCacheCoverage::ReadCMCovFile(const char* file) // if we have a routine name, check for end of routine else { // Totals in arg 0 marks the end of a routine - if (separateLine[0].substr(0, 6) == "Totals") { + if (cmHasLiteralPrefix(separateLine[0], "Totals")) { routine.clear(); // at the end of this routine filepath.clear(); continue; // move to next line diff --git a/Source/CTest/cmParseCacheCoverage.h b/Source/CTest/cmParseCacheCoverage.h index e89b9e454..a8200b787 100644 --- a/Source/CTest/cmParseCacheCoverage.h +++ b/Source/CTest/cmParseCacheCoverage.h @@ -6,7 +6,6 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <string> -#include <vector> #include "cmParseMumpsCoverage.h" @@ -26,13 +25,11 @@ public: protected: // implement virtual from parent - bool LoadCoverageData(const char* dir) override; + bool LoadCoverageData(std::string const& dir) override; // remove files with no coverage void RemoveUnCoveredFiles(); // Read a single mcov file bool ReadCMCovFile(const char* f); - // split a string based on , - bool SplitString(std::vector<std::string>& args, std::string const& line); }; #endif diff --git a/Source/CTest/cmParseCoberturaCoverage.cxx b/Source/CTest/cmParseCoberturaCoverage.cxx index 05da84e2e..711a8564b 100644 --- a/Source/CTest/cmParseCoberturaCoverage.cxx +++ b/Source/CTest/cmParseCoberturaCoverage.cxx @@ -67,7 +67,7 @@ protected: // Check if this is an absolute path that falls within our // source or binary directories. for (std::string const& filePath : FilePaths) { - if (filename.find(filePath) == 0) { + if (cmHasPrefix(filename, filePath)) { this->CurFileName = filename; break; } diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx index 1dc5b7038..14417cc30 100644 --- a/Source/CTest/cmParseGTMCoverage.cxx +++ b/Source/CTest/cmParseGTMCoverage.cxx @@ -19,7 +19,7 @@ cmParseGTMCoverage::cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont, { } -bool cmParseGTMCoverage::LoadCoverageData(const char* d) +bool cmParseGTMCoverage::LoadCoverageData(std::string const& d) { // load all the .mcov files in the specified directory cmsys::Directory dir; diff --git a/Source/CTest/cmParseGTMCoverage.h b/Source/CTest/cmParseGTMCoverage.h index fe0ae0bfd..41cc7f575 100644 --- a/Source/CTest/cmParseGTMCoverage.h +++ b/Source/CTest/cmParseGTMCoverage.h @@ -25,7 +25,7 @@ public: protected: // implement virtual from parent - bool LoadCoverageData(const char* dir) override; + bool LoadCoverageData(std::string const& dir) override; // Read a single mcov file bool ReadMCovFile(const char* f); // find out what line in a mumps file (filepath) the given entry point diff --git a/Source/CTest/cmParseMumpsCoverage.cxx b/Source/CTest/cmParseMumpsCoverage.cxx index b16f1014a..dc3064d22 100644 --- a/Source/CTest/cmParseMumpsCoverage.cxx +++ b/Source/CTest/cmParseMumpsCoverage.cxx @@ -39,9 +39,9 @@ bool cmParseMumpsCoverage::ReadCoverageFile(const char* file) std::string type = line.substr(0, pos); std::string path = line.substr(pos + 1); if (type == "packages") { - this->LoadPackages(path.c_str()); + this->LoadPackages(path); } else if (type == "coverage_dir") { - this->LoadCoverageData(path.c_str()); + this->LoadCoverageData(path); } else { cmCTestLog(this->CTest, ERROR_MESSAGE, "Parse Error in Mumps coverage file :\n" @@ -105,7 +105,7 @@ void cmParseMumpsCoverage::InitializeMumpsFile(std::string& file) } } -bool cmParseMumpsCoverage::LoadPackages(const char* d) +bool cmParseMumpsCoverage::LoadPackages(std::string const& d) { cmsys::Glob glob; glob.RecurseOn(); @@ -113,7 +113,8 @@ bool cmParseMumpsCoverage::LoadPackages(const char* d) glob.FindFiles(pat); for (std::string& file : glob.GetFiles()) { std::string name = cmSystemTools::GetFilenameName(file); - this->RoutineToDirectory[name.substr(0, name.size() - 2)] = file; + name.erase(name.size() - 2); + this->RoutineToDirectory[name] = file; // initialize each file, this is left out until CDash is fixed // to handle large numbers of files this->InitializeMumpsFile(file); diff --git a/Source/CTest/cmParseMumpsCoverage.h b/Source/CTest/cmParseMumpsCoverage.h index 2c544954b..8c0870254 100644 --- a/Source/CTest/cmParseMumpsCoverage.h +++ b/Source/CTest/cmParseMumpsCoverage.h @@ -29,10 +29,10 @@ public: protected: // sub classes will use this to // load all coverage files found in the given directory - virtual bool LoadCoverageData(const char* d) = 0; + virtual bool LoadCoverageData(std::string const& d) = 0; // search the package directory for mumps files and fill // in the RoutineToDirectory map - bool LoadPackages(const char* dir); + bool LoadPackages(std::string const& dir); // initialize the coverage information for a single mumps file void InitializeMumpsFile(std::string& file); // Find mumps file for routine diff --git a/Source/CTest/cmParsePHPCoverage.cxx b/Source/CTest/cmParsePHPCoverage.cxx index a494b92b9..044f518ef 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 6097aa5bd..a549117ca 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -5,6 +5,7 @@ #include <csignal> #include <iostream> #include <string> +#include <utility> #include <cmext/algorithm> @@ -16,14 +17,13 @@ #include "cmGetPipes.h" #include "cmStringAlgorithms.h" #if defined(_WIN32) -# include "cm_kwiml.h" +# include <cm3p/kwiml/int.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(); @@ -69,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; @@ -84,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; @@ -127,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; @@ -135,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; @@ -152,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); @@ -222,7 +222,7 @@ void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf) cm::append(this->Output, strdata); while (this->Output.GetLine(line)) { - this->Runner.CheckOutput(line); + this->Runner->CheckOutput(line); line.clear(); } @@ -236,13 +236,13 @@ 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; @@ -339,7 +339,7 @@ void cmProcess::Finish() if (this->TotalTime <= cmDuration::zero()) { this->TotalTime = cmDuration::zero(); } - this->Runner.FinalizeTest(); + this->Runner->FinalizeTest(); } cmProcess::State cmProcess::GetProcessStatus() diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index ea72a2650..1e6578cf9 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -6,14 +6,15 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <chrono> +#include <memory> #include <string> +#include <utility> #include <vector> +#include <cm3p/uv.h> #include <stddef.h> #include <stdint.h> -#include "cm_uv.h" - #include "cmDuration.h" #include "cmProcessOutput.h" #include "cmUVHandlePtr.h" @@ -28,7 +29,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 +71,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 +88,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/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake index 2a6774885..50ccc7c86 100644 --- a/Source/Checks/cm_cxx_features.cmake +++ b/Source/Checks/cm_cxx_features.cmake @@ -36,8 +36,6 @@ function(cm_check_cxx_feature name) string(REGEX REPLACE "[^\n]*icpc: command line warning #10121: overriding [^\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) diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx index 01fce8545..9a26db599 100644 --- a/Source/CursesDialog/ccmake.cxx +++ b/Source/CursesDialog/ccmake.cxx @@ -16,6 +16,7 @@ #include "cmDocumentation.h" #include "cmDocumentationEntry.h" // IWYU pragma: keep #include "cmState.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmake.h" @@ -111,8 +112,8 @@ int main(int argc, char const* const* argv) std::string cacheDir = cmSystemTools::GetCurrentWorkingDirectory(); for (i = 1; i < args.size(); ++i) { - std::string arg = args[i]; - if (arg.find("-B", 0) == 0) { + std::string const& arg = args[i]; + if (cmHasPrefix(arg, "-B")) { cacheDir = arg.substr(2); } } diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx index 4d3131b07..35f09fd6a 100644 --- a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx +++ b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx @@ -15,6 +15,7 @@ #include "cmCursesPathWidget.h" #include "cmCursesStringWidget.h" #include "cmCursesWidget.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -48,42 +49,42 @@ cmCursesCacheEntryComposite::cmCursesCacheEntryComposite( this->IsNewLabel = cm::make_unique<cmCursesLabelWidget>(1, 1, 1, 1, " "); } - const char* value = state->GetCacheEntryValue(key); + cmProp value = state->GetCacheEntryValue(key); assert(value); switch (state->GetCacheEntryType(key)) { case cmStateEnums::BOOL: { auto bw = cm::make_unique<cmCursesBoolWidget>(this->EntryWidth, 1, 1, 1); - bw->SetValueAsBool(cmIsOn(value)); + bw->SetValueAsBool(cmIsOn(*value)); this->Entry = std::move(bw); break; } case cmStateEnums::PATH: { auto pw = cm::make_unique<cmCursesPathWidget>(this->EntryWidth, 1, 1, 1); - pw->SetString(value); + pw->SetString(*value); this->Entry = std::move(pw); break; } case cmStateEnums::FILEPATH: { auto fpw = cm::make_unique<cmCursesFilePathWidget>(this->EntryWidth, 1, 1, 1); - fpw->SetString(value); + fpw->SetString(*value); this->Entry = std::move(fpw); break; } case cmStateEnums::STRING: { - const char* stringsProp = state->GetCacheEntryProperty(key, "STRINGS"); + cmProp stringsProp = state->GetCacheEntryProperty(key, "STRINGS"); if (stringsProp) { auto ow = cm::make_unique<cmCursesOptionsWidget>(this->EntryWidth, 1, 1, 1); - for (std::string const& opt : cmExpandedList(stringsProp)) { + for (std::string const& opt : cmExpandedList(*stringsProp)) { ow->AddOption(opt); } - ow->SetOption(value); + ow->SetOption(*value); this->Entry = std::move(ow); } else { auto sw = cm::make_unique<cmCursesStringWidget>(this->EntryWidth, 1, 1, 1); - sw->SetString(value); + sw->SetString(*value); this->Entry = std::move(sw); } break; diff --git a/Source/CursesDialog/cmCursesColor.cxx b/Source/CursesDialog/cmCursesColor.cxx index 641d48cce..c0b468b60 100644 --- a/Source/CursesDialog/cmCursesColor.cxx +++ b/Source/CursesDialog/cmCursesColor.cxx @@ -2,6 +2,12 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCursesColor.h" +#include <cctype> +#include <cstdlib> +#include <cstring> +#include <unordered_map> +#include <utility> + #include "cmCursesStandardIncludes.h" bool cmCursesColor::HasColors() @@ -19,11 +25,54 @@ void cmCursesColor::InitColors() 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); + init_pair(BoolOff, GetColor('N', COLOR_RED), -1); + init_pair(BoolOn, GetColor('Y', COLOR_GREEN), -1); + init_pair(String, GetColor('S', COLOR_CYAN), -1); + init_pair(Path, GetColor('P', COLOR_YELLOW), -1); + init_pair(Choice, GetColor('C', COLOR_MAGENTA), -1); } #endif } + +short cmCursesColor::GetColor(char id, short fallback) +{ + static bool initialized = false; + static std::unordered_map<char, short> env; + + if (!initialized) { + if (auto* v = getenv("CCMAKE_COLORS")) { + while (v[0] && v[1] && v[1] == '=') { + auto const n = std::toupper(*v); + + char buffer[12]; + memset(buffer, 0, sizeof(buffer)); + + if (auto* const e = strchr(v, ':')) { + if (static_cast<size_t>(e - v) > sizeof(buffer)) { + break; + } + + strncpy(buffer, v + 2, static_cast<size_t>(e - v - 2)); + v = e + 1; + } else { + auto const l = strlen(v); + if (l > sizeof(buffer)) { + break; + } + + strncpy(buffer, v + 2, l - 2); + v += l; + } + + auto const c = atoi(buffer); + if (c && c < COLORS) { + env.emplace(n, static_cast<short>(c)); + } + } + } + initialized = true; + } + + auto const iter = env.find(id); + return (iter == env.end() ? fallback : iter->second); +} diff --git a/Source/CursesDialog/cmCursesColor.h b/Source/CursesDialog/cmCursesColor.h index 78ca52cbb..f83265f05 100644 --- a/Source/CursesDialog/cmCursesColor.h +++ b/Source/CursesDialog/cmCursesColor.h @@ -13,12 +13,15 @@ public: BoolOn, String, Path, - Options + Choice }; static bool HasColors(); static void InitColors(); + +protected: + static short GetColor(char id, short fallback); }; #endif // cmCursesColor_h diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx index afd2b6b90..591c546e6 100644 --- a/Source/CursesDialog/cmCursesLongMessageForm.cxx +++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx @@ -41,7 +41,8 @@ void cmCursesLongMessageForm::UpdateContent(std::string const& output, this->Title = title; if (!output.empty() && this->Messages.size() < MAX_CONTENT_SIZE) { - this->Messages.append("\n" + output); + this->Messages.push_back('\n'); + this->Messages.append(output); form_driver(this->Form, REQ_NEW_LINE); this->DrawMessage(output.c_str()); } @@ -67,7 +68,7 @@ void cmCursesLongMessageForm::UpdateStatusBar() bar[i] = ' '; } int width; - if (x < cmCursesMainForm::MAX_WIDTH) { + if (x >= 0 && x < cmCursesMainForm::MAX_WIDTH) { width = x; } else { width = cmCursesMainForm::MAX_WIDTH - 1; diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index 65376d1a2..6fc556c08 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -17,6 +17,7 @@ #include "cmCursesStandardIncludes.h" #include "cmCursesStringWidget.h" #include "cmCursesWidget.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -161,7 +162,7 @@ void cmCursesMainForm::RePost() // If normal mode, count only non-advanced entries this->NumberOfVisibleEntries = 0; for (cmCursesCacheEntryComposite& entry : this->Entries) { - const char* existingValue = + cmProp existingValue = this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); bool advanced = this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( @@ -182,7 +183,7 @@ void cmCursesMainForm::RePost() // Assign fields for (cmCursesCacheEntryComposite& entry : this->Entries) { - const char* existingValue = + cmProp existingValue = this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); bool advanced = this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( @@ -241,7 +242,7 @@ void cmCursesMainForm::Render(int left, int top, int width, int height) // If normal, display only non-advanced entries this->NumberOfVisibleEntries = 0; for (cmCursesCacheEntryComposite& entry : this->Entries) { - const char* existingValue = + cmProp existingValue = this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); bool advanced = this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( @@ -259,7 +260,7 @@ void cmCursesMainForm::Render(int left, int top, int width, int height) bool isNewPage; int i = 0; for (cmCursesCacheEntryComposite& entry : this->Entries) { - const char* existingValue = + cmProp existingValue = this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); bool advanced = this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( @@ -405,11 +406,12 @@ void cmCursesMainForm::UpdateStatusBar(cm::optional<std::string> message) // Get the help string of the current entry // and add it to the help string auto cmakeState = this->CMakeInstance->GetState(); - const char* existingValue = cmakeState->GetCacheEntryValue(labelValue); + cmProp existingValue = cmakeState->GetCacheEntryValue(labelValue); if (existingValue) { - auto help = cmakeState->GetCacheEntryProperty(labelValue, "HELPSTRING"); + cmProp help = + cmakeState->GetCacheEntryProperty(labelValue, "HELPSTRING"); if (help) { - bar += help; + bar += *help; } } } @@ -616,10 +618,10 @@ void cmCursesMainForm::FillCacheManagerFromUI() { for (cmCursesCacheEntryComposite& entry : this->Entries) { const std::string& cacheKey = entry.Key; - const char* existingValue = + cmProp existingValue = this->CMakeInstance->GetState()->GetCacheEntryValue(cacheKey); if (existingValue) { - std::string oldValue = existingValue; + std::string oldValue = *existingValue; std::string newValue = entry.Entry->GetValue(); std::string fixedOldValue; std::string fixedNewValue; @@ -802,9 +804,9 @@ void cmCursesMainForm::HandleInput() cmCursesWidget* lbl = reinterpret_cast<cmCursesWidget*>( field_userptr(this->Fields[findex - 2])); const char* curField = lbl->GetValue(); - const char* helpString = nullptr; + cmProp helpString = nullptr; - const char* existingValue = + cmProp existingValue = this->CMakeInstance->GetState()->GetCacheEntryValue(curField); if (existingValue) { helpString = this->CMakeInstance->GetState()->GetCacheEntryProperty( @@ -813,7 +815,7 @@ void cmCursesMainForm::HandleInput() if (helpString) { this->HelpMessage[1] = cmStrCat("Current option is: ", curField, '\n', - "Help string for this option is: ", helpString, '\n'); + "Help string for this option is: ", *helpString, '\n'); } else { this->HelpMessage[1] = ""; } @@ -852,11 +854,7 @@ void cmCursesMainForm::HandleInput() } // switch advanced on/off else if (key == 't') { - if (this->AdvancedMode) { - this->AdvancedMode = false; - } else { - this->AdvancedMode = true; - } + this->AdvancedMode = !this->AdvancedMode; getmaxyx(stdscr, y, x); this->RePost(); this->Render(1, 1, x, y); diff --git a/Source/CursesDialog/cmCursesOptionsWidget.cxx b/Source/CursesDialog/cmCursesOptionsWidget.cxx index a15241fae..8df32e2f3 100644 --- a/Source/CursesDialog/cmCursesOptionsWidget.cxx +++ b/Source/CursesDialog/cmCursesOptionsWidget.cxx @@ -17,8 +17,8 @@ cmCursesOptionsWidget::cmCursesOptionsWidget(int width, int height, int left, // the widget into a string widget at some point. BOOL is safe for // now. if (cmCursesColor::HasColors()) { - set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Options)); - set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Options)); + set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Choice)); + set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Choice)); } else { set_field_fore(this->Field, A_NORMAL); set_field_back(this->Field, A_STANDOUT); diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx index c62947836..4830d6305 100644 --- a/Source/CursesDialog/cmCursesStringWidget.cxx +++ b/Source/CursesDialog/cmCursesStringWidget.cxx @@ -105,12 +105,10 @@ bool cmCursesStringWidget::HandleInput(int& key, cmCursesMainForm* fm, if (!this->InEdit && (key != 10 && key != KEY_ENTER && key != 'i')) { return false; } - // enter edit with return and i (vim binding) - if (!this->InEdit && (key == 10 || key == KEY_ENTER || key == 'i')) { - this->OnReturn(fm, w); - } - // leave edit with return (but not i -- not a toggle) - else if (this->InEdit && (key == 10 || key == KEY_ENTER)) { + // toggle edit with return + if ((key == 10 || key == KEY_ENTER) + // enter edit with i (and not-edit mode) + || (!this->InEdit && key == 'i')) { this->OnReturn(fm, w); } else if (key == KEY_DOWN || key == ctrl('n') || key == KEY_UP || key == ctrl('p') || key == KEY_NPAGE || key == ctrl('d') || diff --git a/Source/LexerParser/cmListFileLexer.c b/Source/LexerParser/cmListFileLexer.c index 15dcda04a..ec7424c4f 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 fdf14d2d3..94cf8a594 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/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index ee81a7d62..9d928b2ff 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -201,8 +201,7 @@ int main(int argc, char** argv) cmSystemTools::CollapseFullPath(args[1].toLocal8Bit().data()); // check if argument is a directory containing CMakeCache.txt - std::string buildFilePath = - cmSystemTools::CollapseFullPath("CMakeCache.txt", filePath.c_str()); + std::string buildFilePath = cmStrCat(filePath, "/CMakeCache.txt"); // check if argument is a CMakeCache.txt file if (cmSystemTools::GetFilenameName(filePath) == "CMakeCache.txt" && @@ -211,8 +210,7 @@ int main(int argc, char** argv) } // check if argument is a directory containing CMakeLists.txt - std::string srcFilePath = - cmSystemTools::CollapseFullPath("CMakeLists.txt", filePath.c_str()); + std::string srcFilePath = cmStrCat(filePath, "/CMakeLists.txt"); if (cmSystemTools::FileExists(buildFilePath.c_str())) { dialog.setBinaryDirectory(QString::fromLocal8Bit( diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index 436a90466..6dbfe1125 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() @@ -595,7 +595,11 @@ void CMakeSetupDialog::doHelp() QDialog dialog; QFontMetrics met(this->font()); +#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) + int msgWidth = met.horizontalAdvance(msg); +#else int msgWidth = met.width(msg); +#endif dialog.setMinimumSize(msgWidth / 15, 20); dialog.setWindowTitle(tr("Help")); QVBoxLayout* l = new QVBoxLayout(&dialog); @@ -804,12 +808,19 @@ bool CMakeSetupDialog::setupFirstConfigure() QString systemVersion = dialog.getSystemVersion(); m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_VERSION", tr("CMake System Version"), systemVersion, false); + QString systemProcessor = dialog.getSystemProcessor(); + m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_PROCESSOR", + tr("CMake System Processor"), systemProcessor, false); QString cxxCompiler = dialog.getCXXCompiler(); - m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER", - tr("CXX compiler."), cxxCompiler, false); + if (!cxxCompiler.isEmpty()) { + m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER", + tr("CXX compiler."), cxxCompiler, false); + } QString cCompiler = dialog.getCCompiler(); - m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER", - tr("C compiler."), cCompiler, false); + if (!cCompiler.isEmpty()) { + m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER", + tr("C compiler."), cCompiler, false); + } } else if (dialog.crossCompilerToolChainFile()) { QString toolchainFile = dialog.getCrossCompilerToolChainFile(); m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE", @@ -1049,14 +1060,7 @@ void CMakeSetupDialog::enterState(CMakeSetupDialog::State s) this->GenerateAction->setEnabled(false); this->OpenProjectButton->setEnabled(false); this->GenerateButton->setText(tr("&Stop")); - } else if (s == ReadyConfigure) { - this->setEnabledState(true); - this->GenerateButton->setEnabled(true); - this->GenerateAction->setEnabled(true); - this->ConfigureButton->setEnabled(true); - this->ConfigureButton->setText(tr("&Configure")); - this->GenerateButton->setText(tr("&Generate")); - } else if (s == ReadyGenerate) { + } else if (s == ReadyConfigure || s == ReadyGenerate) { this->setEnabledState(true); this->GenerateButton->setEnabled(true); this->GenerateAction->setEnabled(true); @@ -1206,7 +1210,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 +1224,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 f23aee6e8..d1e20354b 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 ca28b1972..3c24b9b05 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 d1db5bff6..c26f48984 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 a9089e52f..776af81ff 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "QCMake.h" +#include <cm/memory> + #include <QCoreApplication> #include <QDir> @@ -35,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( @@ -55,11 +58,7 @@ QCMake::QCMake(QObject* p) } } -QCMake::~QCMake() -{ - delete this->CMakeInstance; - // cmDynamicLoader::FlushCache(); -} +QCMake::~QCMake() = default; void QCMake::loadCache(const QString& dir) { @@ -101,29 +100,28 @@ void QCMake::setBinaryDirectory(const QString& _dir) QCMakePropertyList props = this->properties(); emit this->propertiesChanged(props); - const char* homeDir = state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY"); + cmProp homeDir = state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY"); if (homeDir) { - setSourceDirectory(QString::fromLocal8Bit(homeDir)); + setSourceDirectory(QString::fromLocal8Bit(homeDir->c_str())); } - const char* gen = state->GetCacheEntryValue("CMAKE_GENERATOR"); + cmProp gen = state->GetCacheEntryValue("CMAKE_GENERATOR"); if (gen) { const std::string* extraGen = state->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR"); std::string curGen = cmExternalMakefileProjectGenerator::CreateFullGeneratorName( - gen, extraGen ? *extraGen : ""); + *gen, extraGen ? *extraGen : ""); this->setGenerator(QString::fromLocal8Bit(curGen.c_str())); } - const char* platform = - state->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM"); + cmProp platform = state->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM"); if (platform) { - this->setPlatform(QString::fromLocal8Bit(platform)); + this->setPlatform(QString::fromLocal8Bit(platform->c_str())); } - const char* toolset = state->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET"); + cmProp toolset = state->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET"); if (toolset) { - this->setToolset(QString::fromLocal8Bit(toolset)); + this->setToolset(QString::fromLocal8Bit(toolset->c_str())); } checkOpenPossible(); @@ -304,27 +302,28 @@ QCMakePropertyList QCMake::properties() const continue; } - const char* cachedValue = state->GetCacheEntryValue(key); + cmProp cachedValue = state->GetCacheEntryValue(key); QCMakeProperty prop; prop.Key = QString::fromLocal8Bit(key.c_str()); - prop.Help = - QString::fromLocal8Bit(state->GetCacheEntryProperty(key, "HELPSTRING")); - prop.Value = QString::fromLocal8Bit(cachedValue); + if (cmProp hs = state->GetCacheEntryProperty(key, "HELPSTRING")) { + prop.Help = QString::fromLocal8Bit(hs->c_str()); + } + prop.Value = QString::fromLocal8Bit(cachedValue->c_str()); prop.Advanced = state->GetCacheEntryPropertyAsBool(key, "ADVANCED"); if (t == cmStateEnums::BOOL) { prop.Type = QCMakeProperty::BOOL; - prop.Value = cmIsOn(cachedValue); + prop.Value = cmIsOn(*cachedValue); } else if (t == cmStateEnums::PATH) { prop.Type = QCMakeProperty::PATH; } else if (t == cmStateEnums::FILEPATH) { prop.Type = QCMakeProperty::FILEPATH; } else if (t == cmStateEnums::STRING) { prop.Type = QCMakeProperty::STRING; - const char* stringsProperty = - state->GetCacheEntryProperty(key, "STRINGS"); + cmProp stringsProperty = state->GetCacheEntryProperty(key, "STRINGS"); if (stringsProperty) { - prop.Strings = QString::fromLocal8Bit(stringsProperty).split(";"); + prop.Strings = + QString::fromLocal8Bit(stringsProperty->c_str()).split(";"); } } diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h index fa4451bc2..110a971d0 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/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx index 3e6a49e09..b1f4a8229 100644 --- a/Source/QtDialog/QCMakeCacheView.cxx +++ b/Source/QtDialog/QCMakeCacheView.cxx @@ -209,18 +209,35 @@ void QCMakeCacheModel::clear() void QCMakeCacheModel::setProperties(const QCMakePropertyList& props) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + this->beginResetModel(); +#endif + QSet<QCMakeProperty> newProps; QSet<QCMakeProperty> newProps2; if (this->ShowNewProperties) { +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) newProps = props.toSet(); +#else + newProps = QSet<QCMakeProperty>(props.begin(), props.end()); +#endif newProps2 = newProps; +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) QSet<QCMakeProperty> oldProps = this->properties().toSet(); +#else + QSet<QCMakeProperty> oldProps = QSet<QCMakeProperty>( + this->properties().begin(), this->properties().end()); +#endif oldProps.intersect(newProps); newProps.subtract(oldProps); newProps2.subtract(newProps); } else { +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) newProps2 = props.toSet(); +#else + newProps2 = QSet<QCMakeProperty>(props.begin(), props.end()); +#endif } bool b = this->blockSignals(true); @@ -229,10 +246,15 @@ void QCMakeCacheModel::setProperties(const QCMakePropertyList& props) this->NewPropertyCount = newProps.size(); if (View == FlatView) { - QCMakePropertyList newP = newProps.toList(); - QCMakePropertyList newP2 = newProps2.toList(); + QCMakePropertyList newP = newProps.values(); + QCMakePropertyList newP2 = newProps2.values(); +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + std::sort(newP.begin(), newP.end()); + std::sort(newP2.begin(), newP2.end()); +#else qSort(newP); qSort(newP2); +#endif int row_count = 0; foreach (QCMakeProperty const& p, newP) { this->insertRow(row_count); @@ -262,10 +284,17 @@ void QCMakeCacheModel::setProperties(const QCMakePropertyList& props) parentItems.append( new QStandardItem(key.isEmpty() ? tr("Ungrouped Entries") : key)); parentItems.append(new QStandardItem()); +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + parentItems[0]->setData(QBrush(QColor(255, 100, 100)), + Qt::BackgroundRole); + parentItems[1]->setData(QBrush(QColor(255, 100, 100)), + Qt::BackgroundRole); +#else parentItems[0]->setData(QBrush(QColor(255, 100, 100)), Qt::BackgroundColorRole); parentItems[1]->setData(QBrush(QColor(255, 100, 100)), Qt::BackgroundColorRole); +#endif parentItems[0]->setData(1, GroupRole); parentItems[1]->setData(1, GroupRole); root->appendRow(parentItems); @@ -305,7 +334,11 @@ void QCMakeCacheModel::setProperties(const QCMakePropertyList& props) } this->blockSignals(b); +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + this->endResetModel(); +#else this->reset(); +#endif } QCMakeCacheModel::ViewType QCMakeCacheModel::viewType() const @@ -315,6 +348,10 @@ QCMakeCacheModel::ViewType QCMakeCacheModel::viewType() const void QCMakeCacheModel::setViewType(QCMakeCacheModel::ViewType t) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + this->beginResetModel(); +#endif + this->View = t; QCMakePropertyList props = this->properties(); @@ -330,7 +367,11 @@ void QCMakeCacheModel::setViewType(QCMakeCacheModel::ViewType t) this->setProperties(oldProps); this->setProperties(props); this->blockSignals(b); +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + this->endResetModel(); +#else this->reset(); +#endif } void QCMakeCacheModel::setPropertyData(const QModelIndex& idx1, @@ -356,10 +397,15 @@ void QCMakeCacheModel::setPropertyData(const QModelIndex& idx1, } if (isNew) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + this->setData(idx1, QBrush(QColor(255, 100, 100)), Qt::BackgroundRole); + this->setData(idx2, QBrush(QColor(255, 100, 100)), Qt::BackgroundRole); +#else this->setData(idx1, QBrush(QColor(255, 100, 100)), Qt::BackgroundColorRole); this->setData(idx2, QBrush(QColor(255, 100, 100)), Qt::BackgroundColorRole); +#endif } } @@ -409,7 +455,11 @@ void QCMakeCacheModel::breakProperties( reorgProps.append((*iter)[0]); iter = tmp.erase(iter); } else { +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + std::sort(iter->begin(), iter->end()); +#else qSort(*iter); +#endif ++iter; } } @@ -639,9 +689,15 @@ QSize QCMakeCacheModelDelegate::sizeHint(const QStyleOptionViewItem& option, // increase to checkbox size QStyleOptionButton opt; opt.QStyleOption::operator=(option); +#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) + sz = sz.expandedTo( + style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &opt, nullptr) + .size()); +#else sz = sz.expandedTo( style->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt, nullptr) .size()); +#endif return sz; } diff --git a/Source/QtDialog/RegexExplorer.cxx b/Source/QtDialog/RegexExplorer.cxx index 746fd8af2..619494069 100644 --- a/Source/QtDialog/RegexExplorer.cxx +++ b/Source/QtDialog/RegexExplorer.cxx @@ -147,9 +147,6 @@ bool RegexExplorer::stripEscapes(std::string& source) } else if (nextc == 'n') { result.append(1, '\n'); in++; - } else if (nextc == 't') { - result.append(1, '\t'); - in++; } else if (isalnum(nextc) || nextc == '\0') { return false; } else { diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx index 0b2750d85..843574013 100644 --- a/Source/bindexplib.cxx +++ b/Source/bindexplib.cxx @@ -64,7 +64,7 @@ */ #include "bindexplib.h" -#include <cstddef> +#include <cstddef> // IWYU pragma: keep #include <sstream> #include <vector> @@ -276,8 +276,9 @@ public: symbol.compare(0, 4, vectorPrefix)) { SectChar = this->SectionHeaders[pSymbolTable->SectionNumber - 1] .Characteristics; - // skip symbols containing a dot - if (symbol.find('.') == std::string::npos) { + // skip symbols containing a dot or are from managed code + if (symbol.find('.') == std::string::npos && + !SymbolIsFromManagedCode(symbol)) { if (!pSymbolTable->Type && (SectChar & IMAGE_SCN_MEM_WRITE)) { // Read only (i.e. constants) must be excluded this->DataSymbols.insert(symbol); @@ -302,6 +303,13 @@ public: } private: + bool SymbolIsFromManagedCode(std::string const& symbol) + { + return symbol == "__t2m" || symbol == "__m2mep" || symbol == "__mep" || + symbol.find("$$F") != std::string::npos || + symbol.find("$$J") != std::string::npos; + } + std::set<std::string>& Symbols; std::set<std::string>& DataSymbols; DWORD_PTR SymbolCount; @@ -352,14 +360,14 @@ bool DumpFileWithLlvmNm(std::string const& nmPath, const char* filename, line.c_str()); return false; } - const std::string sym = line.substr(0, sym_end); const char sym_type = line[sym_end + 1]; + line.resize(sym_end); switch (sym_type) { case 'D': - dataSymbols.insert(sym); + dataSymbols.insert(line); break; case 'T': - symbols.insert(sym); + symbols.insert(line); break; } } diff --git a/Source/cmAddExecutableCommand.cxx b/Source/cmAddExecutableCommand.cxx index e738bc467..9dd8a1921 100644 --- a/Source/cmAddExecutableCommand.cxx +++ b/Source/cmAddExecutableCommand.cxx @@ -117,14 +117,9 @@ bool cmAddExecutableCommand(std::vector<std::string> const& args, "\" is not an executable.")); return false; } - if (aliasedTarget->IsImported() && - !aliasedTarget->IsImportedGloballyVisible()) { - status.SetError(cmStrCat("cannot create ALIAS target \"", exename, - "\" because target \"", aliasedName, - "\" is imported but not globally visible.")); - return false; - } - mf.AddAlias(exename, aliasedName); + mf.AddAlias(exename, aliasedName, + !aliasedTarget->IsImported() || + aliasedTarget->IsImportedGloballyVisible()); return true; } diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index f443fc664..3e5d76484 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -9,6 +9,7 @@ #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmPolicies.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -181,6 +182,16 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args, return false; } + if (mf.GetPolicyStatus(cmPolicies::CMP0107) == cmPolicies::NEW) { + // Make sure the target does not already exist. + if (mf.FindTargetToUse(libName)) { + status.SetError(cmStrCat( + "cannot create ALIAS target \"", libName, + "\" because another target with the same name already exists.")); + return false; + } + } + std::string const& aliasedName = *s; if (mf.IsAlias(aliasedName)) { status.SetError(cmStrCat("cannot create ALIAS target \"", libName, @@ -208,14 +219,9 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args, "\" is not a library.")); return false; } - if (aliasedTarget->IsImported() && - !aliasedTarget->IsImportedGloballyVisible()) { - status.SetError(cmStrCat("cannot create ALIAS target \"", libName, - "\" because target \"", aliasedName, - "\" is imported but not globally visible.")); - return false; - } - mf.AddAlias(libName, aliasedName); + mf.AddAlias(libName, aliasedName, + !aliasedTarget->IsImported() || + aliasedTarget->IsImportedGloballyVisible()); return true; } diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx index 35eabafcf..83d630600 100644 --- a/Source/cmAddSubDirectoryCommand.cxx +++ b/Source/cmAddSubDirectoryCommand.cxx @@ -4,6 +4,8 @@ #include <cstring> +#include <cm/string_view> + #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmRange.h" @@ -86,7 +88,8 @@ bool cmAddSubDirectoryCommand(std::vector<std::string> const& args, if (binLen > 0 && bin.back() == '/') { --binLen; } - binPath = bin.substr(0, binLen) + srcPath.substr(srcLen); + binPath = cmStrCat(cm::string_view(bin).substr(0, binLen), + cm::string_view(srcPath).substr(srcLen)); } else { // Use the binary directory specified. // Interpret a relative path with respect to the current binary directory. diff --git a/Source/cmAffinity.cxx b/Source/cmAffinity.cxx index 8f9fe2ad8..35443e795 100644 --- a/Source/cmAffinity.cxx +++ b/Source/cmAffinity.cxx @@ -2,7 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmAffinity.h" -#include "cm_uv.h" +#include <cm3p/uv.h> #ifndef CMAKE_USE_SYSTEM_LIBUV # ifdef _WIN32 diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h index c0ac5512a..c8e8dcb85 100644 --- a/Source/cmAlgorithms.h +++ b/Source/cmAlgorithms.h @@ -13,20 +13,10 @@ #include <utility> #include <vector> -#include "cm_kwiml.h" +#include <cmext/algorithm> #include "cmRange.h" -template <std::size_t N> -struct cmOverloadPriority : cmOverloadPriority<N - 1> -{ -}; - -template <> -struct cmOverloadPriority<0> -{ -}; - template <typename FwdIt> FwdIt cmRotate(FwdIt first, FwdIt middle, FwdIt last) { @@ -37,34 +27,6 @@ FwdIt cmRotate(FwdIt first, FwdIt middle, FwdIt last) return first; } -template <typename Range, typename Key> -auto cmContainsImpl(Range const& range, Key const& key, cmOverloadPriority<2>) - -> decltype(range.exists(key)) -{ - return range.exists(key); -} - -template <typename Range, typename Key> -auto cmContainsImpl(Range const& range, Key const& key, cmOverloadPriority<1>) - -> decltype(range.find(key) != range.end()) -{ - return range.find(key) != range.end(); -} - -template <typename Range, typename Key> -bool cmContainsImpl(Range const& range, Key const& key, cmOverloadPriority<0>) -{ - using std::begin; - using std::end; - return std::find(begin(range), end(range), key) != end(range); -} - -template <typename Range, typename Key> -bool cmContains(Range const& range, Key const& key) -{ - return cmContainsImpl(range, key, cmOverloadPriority<2>{}); -} - namespace ContainerAlgorithms { template <typename FwdIt> @@ -158,7 +120,7 @@ ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last) ForwardIterator result = first; while (first != last) { - if (!cmContains(uniq, first)) { + if (!cm::contains(uniq, first)) { if (result != first) { *result = std::move(*first); } diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index d29b2acf6..addfbff3e 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -7,12 +7,14 @@ #include <iostream> #include <sstream> +#include <cm3p/archive.h> +#include <cm3p/archive_entry.h> + #include "cmsys/Directory.hxx" #include "cmsys/Encoding.hxx" #include "cmsys/FStream.hxx" #include "cm_get_date.h" -#include "cm_libarchive.h" #include "cmLocale.h" #include "cmStringAlgorithms.h" @@ -170,15 +172,19 @@ cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c, cm_archive_error_string(this->Archive)); return; } +} +bool cmArchiveWrite::Open() +{ if (archive_write_open( this->Archive, this, nullptr, reinterpret_cast<archive_write_callback*>(&Callback::Write), nullptr) != ARCHIVE_OK) { this->Error = cmStrCat("archive_write_open: ", cm_archive_error_string(this->Archive)); - return; + return false; } + return true; } cmArchiveWrite::~cmArchiveWrite() @@ -276,7 +282,12 @@ bool cmArchiveWrite::AddFile(const char* file, size_t skip, const char* prefix) time_t epochTime; iss >> epochTime; if (iss.eof() && !iss.fail()) { + // Set all of the file times to the epoch time to handle archive + // formats that include creation/access time. archive_entry_set_mtime(e, epochTime, 0); + archive_entry_set_atime(e, epochTime, 0); + archive_entry_set_ctime(e, epochTime, 0); + archive_entry_set_birthtime(e, epochTime, 0); } } } @@ -365,3 +376,16 @@ bool cmArchiveWrite::AddData(const char* file, size_t size) } return true; } + +bool cmArchiveWrite::SetFilterOption(const char* module, const char* key, + const char* value) +{ + if (archive_write_set_filter_option(this->Archive, module, key, value) != + ARCHIVE_OK) { + this->Error = "archive_write_set_filter_option: "; + this->Error += cm_archive_error_string(this->Archive); + return false; + } + + return true; +} diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h index e791761cb..b643bce87 100644 --- a/Source/cmArchiveWrite.h +++ b/Source/cmArchiveWrite.h @@ -62,6 +62,8 @@ public: cmArchiveWrite(const cmArchiveWrite&) = delete; cmArchiveWrite& operator=(const cmArchiveWrite&) = delete; + bool Open(); + /** * Add a path (file or directory) to the archive. Directories are * added recursively. The "path" must be readable on disk, either @@ -139,6 +141,9 @@ public: this->Gname = ""; } + //! Set an option on a filter; + bool SetFilterOption(const char* module, const char* key, const char* value); + private: bool Okay() const { return this->Error.empty(); } bool AddPath(const char* path, size_t skip, const char* prefix, diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx index 4c8717749..4624f1c0a 100644 --- a/Source/cmArgumentParser.cxx +++ b/Source/cmArgumentParser.cxx @@ -3,7 +3,6 @@ #include "cmArgumentParser.h" #include <algorithm> -#include <type_traits> namespace ArgumentParser { diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index 94265372a..5d2dfa224 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -12,8 +12,7 @@ #include <vector> #include <cm/string_view> - -#include "cm_static_string_view.hxx" +#include <cmext/string_view> namespace ArgumentParser { diff --git a/Source/cmAuxSourceDirectoryCommand.cxx b/Source/cmAuxSourceDirectoryCommand.cxx index 289bb7217..d6f7500e8 100644 --- a/Source/cmAuxSourceDirectoryCommand.cxx +++ b/Source/cmAuxSourceDirectoryCommand.cxx @@ -6,6 +6,8 @@ #include <cstddef> #include <utility> +#include <cm/string_view> + #include "cmsys/Directory.hxx" #include "cmExecutionStatus.h" @@ -50,11 +52,10 @@ bool cmAuxSourceDirectoryCommand(std::vector<std::string> const& args, // Split the filename into base and extension std::string::size_type dotpos = file.rfind('.'); if (dotpos != std::string::npos) { - std::string ext = file.substr(dotpos + 1); - std::string base = file.substr(0, dotpos); + auto ext = cm::string_view(file).substr(dotpos + 1); // Process only source files auto cm = mf.GetCMakeInstance(); - if (!base.empty() && cm->IsSourceExtension(ext)) { + if (dotpos > 0 && cm->IsSourceExtension(ext)) { std::string fullname = cmStrCat(templateDirectory, '/', file); // add the file as a class file so // depends can be done diff --git a/Source/cmBinUtilsLinuxELFLinker.cxx b/Source/cmBinUtilsLinuxELFLinker.cxx index 0dea8256c..9ce403dcc 100644 --- a/Source/cmBinUtilsLinuxELFLinker.cxx +++ b/Source/cmBinUtilsLinuxELFLinker.cxx @@ -6,6 +6,7 @@ #include <sstream> #include <cm/memory> +#include <cm/string_view> #include <cmsys/RegularExpression.hxx> @@ -26,14 +27,16 @@ static std::string ReplaceOrigin(const std::string& rpath, cmsys::RegularExpressionMatch match; if (originRegex.find(rpath.c_str(), match)) { - std::string begin = rpath.substr(0, match.start(1)); - std::string end = rpath.substr(match.end(1)); - return begin + origin + end; + cm::string_view pathv(rpath); + auto begin = pathv.substr(0, match.start(1)); + auto end = pathv.substr(match.end(1)); + return cmStrCat(begin, origin, end); } if (originCurlyRegex.find(rpath.c_str(), match)) { - std::string begin = rpath.substr(0, match.start()); - std::string end = rpath.substr(match.end()); - return begin + origin + end; + cm::string_view pathv(rpath); + auto begin = pathv.substr(0, match.start()); + auto end = pathv.substr(match.end()); + return cmStrCat(begin, origin, end); } return rpath; } diff --git a/Source/cmBinUtilsMacOSMachOLinker.cxx b/Source/cmBinUtilsMacOSMachOLinker.cxx index 98250b1c0..0f47146c5 100644 --- a/Source/cmBinUtilsMacOSMachOLinker.cxx +++ b/Source/cmBinUtilsMacOSMachOLinker.cxx @@ -14,6 +14,18 @@ #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +namespace { +bool IsMissingSystemDylib(std::string const& path) +{ + // Starting on macOS 11, the dynamic loader has a builtin cache of + // system-provided dylib files that do not exist on the filesystem. + // Tell our caller that these are expected to be missing. + return ((cmHasLiteralPrefix(path, "/System/Library/") || + cmHasLiteralPrefix(path, "/usr/lib/")) && + !cmSystemTools::PathExists(path)); +} +} + cmBinUtilsMacOSMachOLinker::cmBinUtilsMacOSMachOLinker( cmRuntimeDependencyArchive* archive) : cmBinUtilsLinker(archive) @@ -82,7 +94,8 @@ bool cmBinUtilsMacOSMachOLinker::GetFileDependencies( return false; } if (resolved) { - if (!this->Archive->IsPostExcluded(path)) { + if (!this->Archive->IsPostExcluded(path) && + !IsMissingSystemDylib(path)) { auto filename = cmSystemTools::GetFilenameName(path); bool unique; this->Archive->AddResolvedPath(filename, path, unique); diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx index 49c943975..b82fb9aac 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 3e517dca4..ad4d66534 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/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx new file mode 100644 index 000000000..eb9269f7f --- /dev/null +++ b/Source/cmCMakeLanguageCommand.cxx @@ -0,0 +1,137 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCMakeLanguageCommand.h" + +#include <algorithm> +#include <array> +#include <cstddef> +#include <memory> +#include <string> + +#include <cm/string_view> +#include <cmext/string_view> + +#include "cmExecutionStatus.h" +#include "cmListFileCache.h" +#include "cmMakefile.h" +#include "cmRange.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +namespace { +std::array<cm::static_string_view, 12> InvalidCommands{ + { // clang-format off + "function"_s, "endfunction"_s, + "macro"_s, "endmacro"_s, + "if"_s, "elseif"_s, "else"_s, "endif"_s, + "while"_s, "endwhile"_s, + "foreach"_s, "endforeach"_s + } // clang-format on +}; +} + +bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args, + cmExecutionStatus& status) +{ + if (args.empty()) { + status.SetError("called with incorrect number of arguments"); + return false; + } + + cmMakefile& makefile = status.GetMakefile(); + cmListFileContext context = makefile.GetExecutionContext(); + + bool result = false; + + std::vector<std::string> dispatchExpandedArgs; + std::vector<cmListFileArgument> dispatchArgs; + dispatchArgs.emplace_back(args[0]); + makefile.ExpandArguments(dispatchArgs, dispatchExpandedArgs); + + if (dispatchExpandedArgs.empty()) { + status.SetError("called with incorrect number of arguments"); + return false; + } + + if (dispatchExpandedArgs[0] == "CALL") { + if ((args.size() == 1 && dispatchExpandedArgs.size() != 2) || + dispatchExpandedArgs.size() > 2) { + status.SetError("called with incorrect number of arguments"); + return false; + } + + // First argument is the name of the function to call + std::string callCommand; + size_t startArg; + if (dispatchExpandedArgs.size() == 1) { + std::vector<std::string> functionExpandedArg; + std::vector<cmListFileArgument> functionArg; + functionArg.emplace_back(args[1]); + makefile.ExpandArguments(functionArg, functionExpandedArg); + + if (functionExpandedArg.size() != 1) { + status.SetError("called with incorrect number of arguments"); + return false; + } + + callCommand = functionExpandedArg[0]; + startArg = 2; + } else { + callCommand = dispatchExpandedArgs[1]; + startArg = 1; + } + + // ensure specified command is valid + // start/end flow control commands are not allowed + auto cmd = cmSystemTools::LowerCase(callCommand); + if (std::find(InvalidCommands.cbegin(), InvalidCommands.cend(), cmd) != + InvalidCommands.cend()) { + status.SetError(cmStrCat("invalid command specified: "_s, callCommand)); + return false; + } + + cmListFileFunction func; + func.Name = callCommand; + func.Line = context.Line; + + // The rest of the arguments are passed to the function call above + for (size_t i = startArg; i < args.size(); ++i) { + cmListFileArgument lfarg; + lfarg.Delim = args[i].Delim; + lfarg.Line = context.Line; + lfarg.Value = args[i].Value; + func.Arguments.emplace_back(lfarg); + } + + result = makefile.ExecuteCommand(func, status); + } else if (dispatchExpandedArgs[0] == "EVAL") { + std::vector<std::string> expandedArgs; + makefile.ExpandArguments(args, expandedArgs); + + if (expandedArgs.size() < 2) { + status.SetError("called with incorrect number of arguments"); + return false; + } + + if (expandedArgs[1] != "CODE") { + auto code_iter = + std::find(expandedArgs.begin() + 2, expandedArgs.end(), "CODE"); + if (code_iter == expandedArgs.end()) { + status.SetError("called without CODE argument"); + } else { + status.SetError( + "called with unsupported arguments between EVAL and CODE arguments"); + } + return false; + } + + const std::string code = + cmJoin(cmMakeRange(expandedArgs.begin() + 2, expandedArgs.end()), " "); + result = makefile.ReadListFileAsString( + code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL")); + } else { + status.SetError("called with unknown meta-operation"); + } + + return result; +} diff --git a/Source/cmCMakeLanguageCommand.h b/Source/cmCMakeLanguageCommand.h new file mode 100644 index 000000000..73065156b --- /dev/null +++ b/Source/cmCMakeLanguageCommand.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 cmCMakeLanguageCommand_h +#define cmCMakeLanguageCommand_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <vector> + +class cmExecutionStatus; +struct cmListFileArgument; + +/** + * \brief Calls a scripted or build-in command + * + */ +bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args, + cmExecutionStatus& status); + +#endif diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx index b5c7e9693..697d435aa 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -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) @@ -596,12 +580,14 @@ const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop) { cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); if (cmSourceFile* rsf = sf->RealSourceFile) { - return rsf->GetProperty(prop); + cmProp p = rsf->GetProperty(prop); + return p ? p->c_str() : nullptr; } if (!strcmp(prop, "LOCATION")) { return sf->FullPath.c_str(); } - return sf->Properties.GetPropertyValue(prop); + cmProp retVal = sf->Properties.GetPropertyValue(prop); + return retVal ? retVal->c_str() : nullptr; } int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop) @@ -791,8 +777,9 @@ void CCONV DefineSourceFileProperty(void* arg, const char* name, const char* longDocs, int chained) { cmMakefile* mf = static_cast<cmMakefile*>(arg); - mf->GetState()->DefineProperty(name, cmProperty::SOURCE_FILE, briefDocs, - longDocs, chained != 0); + mf->GetState()->DefineProperty(name, cmProperty::SOURCE_FILE, + briefDocs ? briefDocs : "", + longDocs ? longDocs : "", chained != 0); } } // close the extern "C" scope diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 04f75bd50..bca75406b 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -16,6 +16,14 @@ #include <utility> #include <vector> +#include <cm/memory> +#include <cm/string_view> +#include <cmext/algorithm> +#include <cmext/string_view> + +#include <cm3p/curl/curl.h> +#include <cm3p/zlib.h> + #include "cmsys/Base64.h" #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" @@ -23,18 +31,12 @@ #include "cmsys/Process.h" #include "cmsys/RegularExpression.hxx" #include "cmsys/SystemInformation.hxx" - -#include "cm_curl.h" -#include "cm_zlib.h" #if defined(_WIN32) # include <windows.h> // IWYU pragma: keep #else # include <unistd.h> // IWYU pragma: keep #endif -#include <cm/memory> -#include <cmext/algorithm> - #include "cmCTestBuildAndTestHandler.h" #include "cmCTestBuildHandler.h" #include "cmCTestConfigureHandler.h" @@ -52,6 +54,7 @@ #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmProcessOutput.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" @@ -89,6 +92,7 @@ struct cmCTest::Private std::string ConfigType; std::string ScheduleType; std::chrono::system_clock::time_point StopTime; + bool StopOnFailure = false; bool TestProgressOutput = false; bool Verbose = false; bool ExtraVerbose = false; @@ -201,7 +205,7 @@ struct cmCTest::Private int SubmitIndex = 0; - cmGeneratedFileStream* OutputLogFile = nullptr; + std::unique_ptr<cmGeneratedFileStream> OutputLogFile; int OutputLogFileLastTag = -1; bool OutputTestOutputOnTestFailure = false; @@ -271,9 +275,10 @@ bool cmCTest::GetTomorrowTag() const return this->Impl->TomorrowTag; } -std::string cmCTest::CleanString(const std::string& str) +std::string cmCTest::CleanString(const std::string& str, + std::string::size_type spos) { - std::string::size_type spos = str.find_first_not_of(" \n\t\r\f\v"); + spos = str.find_first_not_of(" \n\t\r\f\v", spos); std::string::size_type epos = str.find_last_not_of(" \n\t\r\f\v"); if (spos == std::string::npos) { return std::string(); @@ -362,10 +367,7 @@ cmCTest::cmCTest() cmSystemTools::EnableVSConsoleOutput(); } -cmCTest::~cmCTest() -{ - delete this->Impl->OutputLogFile; -} +cmCTest::~cmCTest() = default; int cmCTest::GetParallelLevel() const { @@ -727,7 +729,7 @@ bool cmCTest::UpdateCTestConfiguration() continue; } while (fin && (line.back() == '\\')) { - line = line.substr(0, line.size() - 1); + line.resize(line.size() - 1); buffer[0] = 0; fin.getline(buffer, 1023); buffer[1023] = 0; @@ -741,7 +743,7 @@ bool cmCTest::UpdateCTestConfiguration() continue; } std::string key = line.substr(0, cpos); - std::string value = cmCTest::CleanString(line.substr(cpos + 1)); + std::string value = cmCTest::CleanString(line, cpos + 1); this->Impl->CTestConfiguration[key] = value; } fin.close(); @@ -1442,16 +1444,15 @@ void cmCTest::AddSiteProperties(cmXMLWriter& xml) return; } // This code should go when cdash is changed to use labels only - const char* subproject = cm->GetState()->GetGlobalProperty("SubProject"); + cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject"); if (subproject) { xml.StartElement("Subproject"); - xml.Attribute("name", subproject); - const char* labels = + xml.Attribute("name", *subproject); + cmProp labels = ch->GetCMake()->GetState()->GetGlobalProperty("SubProjectLabels"); if (labels) { xml.StartElement("Labels"); - std::string l = labels; - std::vector<std::string> args = cmExpandedList(l); + std::vector<std::string> args = cmExpandedList(*labels); for (std::string const& i : args) { xml.Element("Label", i); } @@ -1461,10 +1462,10 @@ void cmCTest::AddSiteProperties(cmXMLWriter& xml) } // This code should stay when cdash only does label based sub-projects - const char* label = cm->GetState()->GetGlobalProperty("Label"); + cmProp label = cm->GetState()->GetGlobalProperty("Label"); if (label) { xml.StartElement("Labels"); - xml.Element("Label", label); + xml.Element("Label", *label); xml.EndElement(); } } @@ -1816,10 +1817,10 @@ void cmCTest::ErrorMessageUnknownDashDValue(std::string& val) << " ctest -D NightlyMemoryCheck" << std::endl); } -bool cmCTest::CheckArgument(const std::string& arg, const char* varg1, +bool cmCTest::CheckArgument(const std::string& arg, cm::string_view varg1, const char* varg2) { - return (varg1 && arg == varg1) || (varg2 && arg == varg2); + return (arg == varg1) || (varg2 && arg == varg2); } // Processes one command line argument (and its arguments if any) @@ -1829,21 +1830,21 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, std::string& errormsg) { std::string arg = args[i]; - if (this->CheckArgument(arg, "-F")) { + if (this->CheckArgument(arg, "-F"_s)) { this->Impl->Failover = true; - } - if (this->CheckArgument(arg, "-j", "--parallel") && i < args.size() - 1) { + } else if (this->CheckArgument(arg, "-j"_s, "--parallel") && + i < args.size() - 1) { i++; int plevel = atoi(args[i].c_str()); this->SetParallelLevel(plevel); this->Impl->ParallelLevelSetInCli = true; - } else if (arg.find("-j") == 0) { + } else if (cmHasPrefix(arg, "-j")) { int plevel = atoi(arg.substr(2).c_str()); this->SetParallelLevel(plevel); this->Impl->ParallelLevelSetInCli = true; } - if (this->CheckArgument(arg, "--repeat-until-fail")) { + else if (this->CheckArgument(arg, "--repeat-until-fail"_s)) { if (i >= args.size() - 1) { errormsg = "'--repeat-until-fail' requires an argument"; return false; @@ -1855,8 +1856,8 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, i++; long repeat = 1; if (!cmStrToLong(args[i], &repeat)) { - errormsg = - "'--repeat-until-fail' given non-integer value '" + args[i] + "'"; + errormsg = cmStrCat("'--repeat-until-fail' given non-integer value '", + args[i], "'"); return false; } this->Impl->RepeatCount = static_cast<int>(repeat); @@ -1865,7 +1866,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, } } - if (this->CheckArgument(arg, "--repeat")) { + else if (this->CheckArgument(arg, "--repeat"_s)) { if (i >= args.size() - 1) { errormsg = "'--repeat' requires an argument"; return false; @@ -1893,12 +1894,12 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, } } } else { - errormsg = "'--repeat' given invalid value '" + args[i] + "'"; + errormsg = cmStrCat("'--repeat' given invalid value '", args[i], "'"); return false; } } - if (this->CheckArgument(arg, "--test-load") && i < args.size() - 1) { + else if (this->CheckArgument(arg, "--test-load"_s) && i < args.size() - 1) { i++; unsigned long load; if (cmStrToULong(args[i], &load)) { @@ -1909,76 +1910,68 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, } } - if (this->CheckArgument(arg, "--no-compress-output")) { + else if (this->CheckArgument(arg, "--no-compress-output"_s)) { this->Impl->CompressTestOutput = false; } - if (this->CheckArgument(arg, "--print-labels")) { + else if (this->CheckArgument(arg, "--print-labels"_s)) { this->Impl->PrintLabels = true; } - if (this->CheckArgument(arg, "--http1.0")) { + else if (this->CheckArgument(arg, "--http1.0"_s)) { this->Impl->UseHTTP10 = true; } - if (this->CheckArgument(arg, "--timeout") && i < args.size() - 1) { + else if (this->CheckArgument(arg, "--timeout"_s) && i < args.size() - 1) { i++; auto timeout = cmDuration(atof(args[i].c_str())); this->Impl->GlobalTimeout = timeout; } - if (this->CheckArgument(arg, "--stop-time") && i < args.size() - 1) { + else if (this->CheckArgument(arg, "--stop-time"_s) && i < args.size() - 1) { i++; this->SetStopTime(args[i]); } - if (this->CheckArgument(arg, "-C", "--build-config") && - i < args.size() - 1) { + else if (this->CheckArgument(arg, "--stop-on-failure"_s)) { + this->Impl->StopOnFailure = true; + } + + else if (this->CheckArgument(arg, "-C"_s, "--build-config") && + i < args.size() - 1) { i++; this->SetConfigType(args[i].c_str()); } - if (this->CheckArgument(arg, "--debug")) { + else if (this->CheckArgument(arg, "--debug"_s)) { this->Impl->Debug = true; this->Impl->ShowLineNumbers = true; - } - if (this->CheckArgument(arg, "--group") && i < args.size() - 1) { + } else if ((this->CheckArgument(arg, "--group"_s) || + // This is an undocumented / deprecated option. + // "Track" has been renamed to "Group". + this->CheckArgument(arg, "--track"_s)) && + i < args.size() - 1) { i++; this->Impl->SpecificGroup = args[i]; - } - // This is an undocumented / deprecated option. - // "Track" has been renamed to "Group". - if (this->CheckArgument(arg, "--track") && i < args.size() - 1) { - i++; - this->Impl->SpecificGroup = args[i]; - } - if (this->CheckArgument(arg, "--show-line-numbers")) { + } else if (this->CheckArgument(arg, "--show-line-numbers"_s)) { this->Impl->ShowLineNumbers = true; - } - if (this->CheckArgument(arg, "--no-label-summary")) { + } else if (this->CheckArgument(arg, "--no-label-summary"_s)) { this->Impl->LabelSummary = false; - } - if (this->CheckArgument(arg, "--no-subproject-summary")) { + } else if (this->CheckArgument(arg, "--no-subproject-summary"_s)) { this->Impl->SubprojectSummary = false; - } - if (this->CheckArgument(arg, "-Q", "--quiet")) { + } else if (this->CheckArgument(arg, "-Q"_s, "--quiet")) { this->Impl->Quiet = true; - } - if (this->CheckArgument(arg, "--progress")) { + } else if (this->CheckArgument(arg, "--progress"_s)) { this->Impl->TestProgressOutput = true; - } - if (this->CheckArgument(arg, "-V", "--verbose")) { + } else if (this->CheckArgument(arg, "-V"_s, "--verbose")) { this->Impl->Verbose = true; - } - if (this->CheckArgument(arg, "-VV", "--extra-verbose")) { + } else if (this->CheckArgument(arg, "-VV"_s, "--extra-verbose")) { this->Impl->ExtraVerbose = true; this->Impl->Verbose = true; - } - if (this->CheckArgument(arg, "--output-on-failure")) { + } else if (this->CheckArgument(arg, "--output-on-failure"_s)) { this->Impl->OutputTestOutputOnTestFailure = true; - } - if (this->CheckArgument(arg, "--test-output-size-passed") && - i < args.size() - 1) { + } else if (this->CheckArgument(arg, "--test-output-size-passed"_s) && + i < args.size() - 1) { i++; long outputSize; if (cmStrToLong(args[i], &outputSize)) { @@ -1988,9 +1981,8 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, "Invalid value for '--test-output-size-passed': " << args[i] << "\n"); } - } - if (this->CheckArgument(arg, "--test-output-size-failed") && - i < args.size() - 1) { + } else if (this->CheckArgument(arg, "--test-output-size-failed"_s) && + i < args.size() - 1) { i++; long outputSize; if (cmStrToLong(args[i], &outputSize)) { @@ -2000,11 +1992,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, "Invalid value for '--test-output-size-failed': " << args[i] << "\n"); } - } - if (this->CheckArgument(arg, "-N", "--show-only")) { + } else if (this->CheckArgument(arg, "-N"_s, "--show-only")) { this->Impl->ShowOnly = true; - } - if (cmHasLiteralPrefix(arg, "--show-only=")) { + } else if (cmHasLiteralPrefix(arg, "--show-only=")) { this->Impl->ShowOnly = true; // Check if a specific format is requested. Defaults to human readable @@ -2022,27 +2012,26 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, } } - if (this->CheckArgument(arg, "-O", "--output-log") && i < args.size() - 1) { + else if (this->CheckArgument(arg, "-O"_s, "--output-log") && + i < args.size() - 1) { i++; this->SetOutputLogFileName(args[i].c_str()); } - if (this->CheckArgument(arg, "--tomorrow-tag")) { + else if (this->CheckArgument(arg, "--tomorrow-tag"_s)) { this->Impl->TomorrowTag = true; - } - if (this->CheckArgument(arg, "--force-new-ctest-process")) { + } else if (this->CheckArgument(arg, "--force-new-ctest-process"_s)) { this->Impl->ForceNewCTestProcess = true; - } - if (this->CheckArgument(arg, "-W", "--max-width") && i < args.size() - 1) { + } else if (this->CheckArgument(arg, "-W"_s, "--max-width") && + i < args.size() - 1) { i++; this->Impl->MaxTestNameWidth = atoi(args[i].c_str()); - } - if (this->CheckArgument(arg, "--interactive-debug-mode") && - i < args.size() - 1) { + } else if (this->CheckArgument(arg, "--interactive-debug-mode"_s) && + i < args.size() - 1) { i++; this->Impl->InteractiveDebugMode = cmIsOn(args[i]); - } - if (this->CheckArgument(arg, "--submit-index") && i < args.size() - 1) { + } else if (this->CheckArgument(arg, "--submit-index"_s) && + i < args.size() - 1) { i++; this->Impl->SubmitIndex = atoi(args[i].c_str()); if (this->Impl->SubmitIndex < 0) { @@ -2050,24 +2039,27 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, } } - if (this->CheckArgument(arg, "--overwrite") && i < args.size() - 1) { + else if (this->CheckArgument(arg, "--overwrite"_s) && i < args.size() - 1) { i++; this->AddCTestConfigurationOverwrite(args[i]); - } - if (this->CheckArgument(arg, "-A", "--add-notes") && i < args.size() - 1) { + } else if (this->CheckArgument(arg, "-A"_s, "--add-notes") && + i < args.size() - 1) { this->Impl->ProduceXML = true; this->SetTest("Notes"); i++; this->SetNotesFiles(args[i].c_str()); + return true; } - const std::string noTestsPrefix = "--no-tests="; + cm::string_view noTestsPrefix = "--no-tests="; if (cmHasPrefix(arg, noTestsPrefix)) { - const std::string noTestsMode = arg.substr(noTestsPrefix.length()); + cm::string_view noTestsMode = + cm::string_view(arg).substr(noTestsPrefix.length()); if (noTestsMode == "error") { this->Impl->NoTestsMode = cmCTest::NoTests::Error; } else if (noTestsMode != "ignore") { - errormsg = "'--no-tests=' given unknown value '" + noTestsMode + "'"; + errormsg = + cmStrCat("'--no-tests=' given unknown value '", noTestsMode, '\''); return false; } else { this->Impl->NoTestsMode = cmCTest::NoTests::Ignore; @@ -2075,34 +2067,32 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, } // options that control what tests are run - if (this->CheckArgument(arg, "-I", "--tests-information") && - i < args.size() - 1) { + else if (this->CheckArgument(arg, "-I"_s, "--tests-information") && + i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption("TestsToRunInformation", args[i].c_str()); this->GetMemCheckHandler()->SetPersistentOption("TestsToRunInformation", args[i].c_str()); - } - if (this->CheckArgument(arg, "-U", "--union")) { + } else if (this->CheckArgument(arg, "-U"_s, "--union")) { this->GetTestHandler()->SetPersistentOption("UseUnion", "true"); this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true"); - } - if (this->CheckArgument(arg, "-R", "--tests-regex") && i < args.size() - 1) { + } else if (this->CheckArgument(arg, "-R"_s, "--tests-regex") && + i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption("IncludeRegularExpression", args[i].c_str()); this->GetMemCheckHandler()->SetPersistentOption("IncludeRegularExpression", args[i].c_str()); - } - if (this->CheckArgument(arg, "-L", "--label-regex") && i < args.size() - 1) { + } else if (this->CheckArgument(arg, "-L"_s, "--label-regex") && + i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption("LabelRegularExpression", args[i].c_str()); this->GetMemCheckHandler()->SetPersistentOption("LabelRegularExpression", args[i].c_str()); - } - if (this->CheckArgument(arg, "-LE", "--label-exclude") && - i < args.size() - 1) { + } else if (this->CheckArgument(arg, "-LE"_s, "--label-exclude") && + i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption( "ExcludeLabelRegularExpression", args[i].c_str()); @@ -2110,8 +2100,8 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, "ExcludeLabelRegularExpression", args[i].c_str()); } - if (this->CheckArgument(arg, "-E", "--exclude-regex") && - i < args.size() - 1) { + else if (this->CheckArgument(arg, "-E"_s, "--exclude-regex") && + i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption("ExcludeRegularExpression", args[i].c_str()); @@ -2119,24 +2109,22 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, args[i].c_str()); } - if (this->CheckArgument(arg, "-FA", "--fixture-exclude-any") && - i < args.size() - 1) { + else if (this->CheckArgument(arg, "-FA"_s, "--fixture-exclude-any") && + i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption( "ExcludeFixtureRegularExpression", args[i].c_str()); this->GetMemCheckHandler()->SetPersistentOption( "ExcludeFixtureRegularExpression", args[i].c_str()); - } - if (this->CheckArgument(arg, "-FS", "--fixture-exclude-setup") && - i < args.size() - 1) { + } else if (this->CheckArgument(arg, "-FS"_s, "--fixture-exclude-setup") && + i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption( "ExcludeFixtureSetupRegularExpression", args[i].c_str()); this->GetMemCheckHandler()->SetPersistentOption( "ExcludeFixtureSetupRegularExpression", args[i].c_str()); - } - if (this->CheckArgument(arg, "-FC", "--fixture-exclude-cleanup") && - i < args.size() - 1) { + } else if (this->CheckArgument(arg, "-FC"_s, "--fixture-exclude-cleanup") && + i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption( "ExcludeFixtureCleanupRegularExpression", args[i].c_str()); @@ -2144,8 +2132,8 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, "ExcludeFixtureCleanupRegularExpression", args[i].c_str()); } - if (this->CheckArgument(arg, "--resource-spec-file") && - i < args.size() - 1) { + else if (this->CheckArgument(arg, "--resource-spec-file"_s) && + i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption("ResourceSpecFile", args[i].c_str()); @@ -2153,7 +2141,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, args[i].c_str()); } - if (this->CheckArgument(arg, "--rerun-failed")) { + else if (this->CheckArgument(arg, "--rerun-failed"_s)) { this->GetTestHandler()->SetPersistentOption("RerunFailed", "true"); this->GetMemCheckHandler()->SetPersistentOption("RerunFailed", "true"); } @@ -2205,7 +2193,7 @@ void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args, bool& SRArgumentSpecified) { std::string arg = args[i]; - if (this->CheckArgument(arg, "-SP", "--script-new-process") && + if (this->CheckArgument(arg, "-SP"_s, "--script-new-process") && i < args.size() - 1) { this->Impl->RunConfigurationScript = true; i++; @@ -2216,7 +2204,8 @@ void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args, } } - if (this->CheckArgument(arg, "-SR", "--script-run") && i < args.size() - 1) { + if (this->CheckArgument(arg, "-SR"_s, "--script-run") && + i < args.size() - 1) { SRArgumentSpecified = true; this->Impl->RunConfigurationScript = true; i++; @@ -2224,7 +2213,7 @@ void cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args, ch->AddConfigurationScript(args[i].c_str(), true); } - if (this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1) { + if (this->CheckArgument(arg, "-S"_s, "--script") && i < args.size() - 1) { this->Impl->RunConfigurationScript = true; i++; cmCTestScriptHandler* ch = this->GetScriptHandler(); @@ -2274,7 +2263,8 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output) // --dashboard: handle a request for a dashboard std::string arg = args[i]; - if (this->CheckArgument(arg, "-D", "--dashboard") && i < args.size() - 1) { + if (this->CheckArgument(arg, "-D"_s, "--dashboard") && + i < args.size() - 1) { this->Impl->ProduceXML = true; i++; std::string targ = args[i]; @@ -2310,7 +2300,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output) } // --extra-submit - if (this->CheckArgument(arg, "--extra-submit") && i < args.size() - 1) { + if (this->CheckArgument(arg, "--extra-submit"_s) && i < args.size() - 1) { this->Impl->ProduceXML = true; this->SetTest("Submit"); i++; @@ -2320,12 +2310,13 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output) } // --build-and-test options - if (this->CheckArgument(arg, "--build-and-test") && i < args.size() - 1) { + if (this->CheckArgument(arg, "--build-and-test"_s) && + i < args.size() - 1) { cmakeAndTest = true; } // --schedule-random - if (this->CheckArgument(arg, "--schedule-random")) { + if (this->CheckArgument(arg, "--schedule-random"_s)) { this->Impl->ScheduleType = "Random"; } @@ -2380,7 +2371,7 @@ bool cmCTest::HandleTestActionArgument(const char* ctestExec, size_t& i, { bool success = true; std::string arg = args[i]; - if (this->CheckArgument(arg, "-T", "--test-action") && + if (this->CheckArgument(arg, "-T"_s, "--test-action") && (i < args.size() - 1)) { this->Impl->ProduceXML = true; i++; @@ -2412,15 +2403,15 @@ bool cmCTest::HandleTestModelArgument(const char* ctestExec, size_t& i, { bool success = true; std::string arg = args[i]; - if (this->CheckArgument(arg, "-M", "--test-model") && + if (this->CheckArgument(arg, "-M"_s, "--test-model") && (i < args.size() - 1)) { i++; std::string const& str = args[i]; - if (cmSystemTools::LowerCase(str) == "nightly") { + if (cmSystemTools::LowerCase(str) == "nightly"_s) { this->SetTestModel(cmCTest::NIGHTLY); - } else if (cmSystemTools::LowerCase(str) == "continuous") { + } else if (cmSystemTools::LowerCase(str) == "continuous"_s) { this->SetTestModel(cmCTest::CONTINUOUS); - } else if (cmSystemTools::LowerCase(str) == "experimental") { + } else if (cmSystemTools::LowerCase(str) == "experimental"_s) { this->SetTestModel(cmCTest::EXPERIMENTAL); } else { success = false; @@ -2507,6 +2498,16 @@ void cmCTest::SetNotesFiles(const char* notes) this->Impl->NotesFiles = notes; } +bool cmCTest::GetStopOnFailure() const +{ + return this->Impl->StopOnFailure; +} + +void cmCTest::SetStopOnFailure(bool stop) +{ + this->Impl->StopOnFailure = stop; +} + std::chrono::system_clock::time_point cmCTest::GetStopTime() const { return this->Impl->StopTime; @@ -2687,7 +2688,7 @@ std::string cmCTest::GetShortPathToFile(const char* cfname) path = "./" + *res; if (path.back() == '/') { - path = path.substr(0, path.size() - 1); + path.resize(path.size() - 1); } } @@ -2738,7 +2739,7 @@ std::string cmCTest::GetSubmitURL() std::string site = this->GetCTestConfiguration("DropSite"); std::string location = this->GetCTestConfiguration("DropLocation"); - url = cmStrCat(method.empty() ? "http" : method, "://"); + url = cmStrCat(method.empty() ? "http" : method, "://"_s); if (!user.empty()) { url += user; if (!password.empty()) { @@ -3086,12 +3087,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 7f8f913a9..a39b8fed4 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -13,6 +13,8 @@ #include <string> #include <vector> +#include <cm/string_view> + #include "cmDuration.h" #include "cmProcessOutput.h" @@ -140,7 +142,8 @@ public: std::string GetTestModelString(); static int GetTestModelFromString(const char* str); - static std::string CleanString(const std::string& str); + static std::string CleanString(const std::string& str, + std::string::size_type spos = 0); std::string GetCTestConfiguration(const std::string& name); void SetCTestConfiguration(const char* name, const char* value, bool suppress = false); @@ -201,6 +204,9 @@ public: bool ShouldCompressTestOutput(); bool CompressString(std::string& str); + bool GetStopOnFailure() const; + void SetStopOnFailure(bool stop); + std::chrono::system_clock::time_point GetStopTime() const; void SetStopTime(std::string const& time); @@ -506,8 +512,8 @@ private: std::vector<std::string> const& files); /** Check if the argument is the one specified */ - bool CheckArgument(const std::string& arg, const char* varg1, - const char* varg2 = nullptr); + static bool CheckArgument(const std::string& arg, cm::string_view varg1, + const char* varg2 = nullptr); /** Output errors from a test */ void OutputTestErrors(std::vector<char> const& process_output); diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index dc9aba187..35bd681c9 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -19,12 +19,6 @@ #include "cmSystemTools.h" #include "cmVersion.h" -cmCacheManager::cmCacheManager() -{ - this->CacheMajorVersion = 0; - this->CacheMinorVersion = 0; -} - void cmCacheManager::CleanCMakeFiles(const std::string& path) { std::string glob = cmStrCat(path, "/CMakeFiles/*.cmake"); @@ -77,7 +71,7 @@ bool cmCacheManager::LoadCache(const std::string& path, bool internal, } while (realbuffer[0] == '/' && realbuffer[1] == '/') { if ((realbuffer[2] == '\\') && (realbuffer[3] == 'n')) { - helpString += "\n"; + helpString += '\n'; helpString += &realbuffer[4]; } else { helpString += &realbuffer[2]; @@ -117,20 +111,20 @@ bool cmCacheManager::LoadCache(const std::string& path, bool internal, } } else { std::ostringstream error; - error << "Parse error in cache file " << cacheFile; - error << " on line " << lineno << ". Offending entry: " << realbuffer; + error << "Parse error in cache file " << cacheFile << " on line " + << lineno << ". Offending entry: " << realbuffer; cmSystemTools::Error(error.str()); } } this->CacheMajorVersion = 0; this->CacheMinorVersion = 0; - if (const std::string* cmajor = + if (cmProp cmajor = this->GetInitializedCacheValue("CMAKE_CACHE_MAJOR_VERSION")) { unsigned int v = 0; if (sscanf(cmajor->c_str(), "%u", &v) == 1) { this->CacheMajorVersion = v; } - if (const std::string* cminor = + if (cmProp cminor = this->GetInitializedCacheValue("CMAKE_CACHE_MINOR_VERSION")) { if (sscanf(cminor->c_str(), "%u", &v) == 1) { this->CacheMinorVersion = v; @@ -150,8 +144,7 @@ bool cmCacheManager::LoadCache(const std::string& path, bool internal, } // check to make sure the cache directory has not // been moved - const std::string* oldDir = - this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR"); + cmProp oldDir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR"); if (internal && oldDir) { std::string currentcwd = path; std::string oldcwd = *oldDir; @@ -159,8 +152,7 @@ bool cmCacheManager::LoadCache(const std::string& path, bool internal, currentcwd += "/CMakeCache.txt"; oldcwd += "/CMakeCache.txt"; if (!cmSystemTools::SameFile(oldcwd, currentcwd)) { - const std::string* dir = - this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR"); + cmProp dir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR"); std::ostringstream message; message << "The current CMakeCache.txt directory " << currentcwd << " is different than the directory " << (dir ? *dir : "") @@ -174,10 +166,10 @@ bool cmCacheManager::LoadCache(const std::string& path, bool internal, } const char* cmCacheManager::PersistentProperties[] = { "ADVANCED", "MODIFIED", - "STRINGS", nullptr }; + "STRINGS" }; -bool cmCacheManager::ReadPropertyEntry(std::string const& entryKey, - CacheEntry& e) +bool cmCacheManager::ReadPropertyEntry(const std::string& entryKey, + const CacheEntry& e) { // All property entries are internal. if (e.Type != cmStateEnums::INTERNAL) { @@ -185,20 +177,18 @@ bool cmCacheManager::ReadPropertyEntry(std::string const& entryKey, } const char* end = entryKey.c_str() + entryKey.size(); - for (const char** p = cmCacheManager::PersistentProperties; *p; ++p) { - std::string::size_type plen = strlen(*p) + 1; + for (const char* p : cmCacheManager::PersistentProperties) { + std::string::size_type plen = strlen(p) + 1; if (entryKey.size() > plen && *(end - plen) == '-' && - strcmp(end - plen + 1, *p) == 0) { + strcmp(end - plen + 1, p) == 0) { std::string key = entryKey.substr(0, entryKey.size() - plen); - cmCacheManager::CacheIterator it = this->GetCacheIterator(key); - if (it.IsAtEnd()) { + if (auto entry = this->GetCacheEntry(key)) { + // Store this property on its entry. + entry->SetProperty(p, e.Value.c_str()); + } else { // Create an entry and store the property. CacheEntry& ne = this->Cache[key]; - ne.Type = cmStateEnums::UNINITIALIZED; - ne.SetProperty(*p, e.Value.c_str()); - } else { - // Store this property on its entry. - it.SetProperty(*p, e.Value.c_str()); + ne.SetProperty(p, e.Value.c_str()); } return true; } @@ -206,21 +196,23 @@ bool cmCacheManager::ReadPropertyEntry(std::string const& entryKey, return false; } -void cmCacheManager::WritePropertyEntries(std::ostream& os, CacheIterator i, - cmMessenger* messenger) +void cmCacheManager::WritePropertyEntries(std::ostream& os, + const std::string& entryKey, + const CacheEntry& e, + cmMessenger* messenger) const { - for (const char** p = cmCacheManager::PersistentProperties; *p; ++p) { - if (const char* value = i.GetProperty(*p)) { + for (const char* p : cmCacheManager::PersistentProperties) { + if (cmProp value = e.GetProperty(p)) { std::string helpstring = - cmStrCat(*p, " property for variable: ", i.GetName()); + cmStrCat(p, " property for variable: ", entryKey); cmCacheManager::OutputHelpString(os, helpstring); - std::string key = cmStrCat(i.GetName(), '-', *p); + std::string key = cmStrCat(entryKey, '-', p); cmCacheManager::OutputKey(os, key); os << ":INTERNAL="; - cmCacheManager::OutputValue(os, value); - os << "\n"; - cmCacheManager::OutputNewlineTruncationWarning(os, key, value, + cmCacheManager::OutputValue(os, *value); + os << '\n'; + cmCacheManager::OutputNewlineTruncationWarning(os, key, *value, messenger); } } @@ -270,31 +262,29 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger) /* clang-format off */ fout << "# This is the CMakeCache file.\n" - << "# For build in directory: " << currentcwd << "\n" - << "# It was generated by CMake: " - << cmSystemTools::GetCMakeCommand() << std::endl; - /* clang-format on */ - - /* clang-format off */ - fout << "# You can edit this file to change values found and used by cmake." - << std::endl - << "# If you do not want to change any of the values, simply exit the " - "editor." << std::endl - << "# If you do want to change a value, simply edit, save, and exit " - "the editor." << std::endl - << "# The syntax for the file is as follows:\n" - << "# KEY:TYPE=VALUE\n" - << "# KEY is the name of a variable in the cache.\n" - << "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT " - "TYPE!." << std::endl - << "# VALUE is the current value for the KEY.\n\n"; + "# For build in directory: " << currentcwd << "\n" + "# It was generated by CMake: " + << cmSystemTools::GetCMakeCommand() + << "\n" + "# You can edit this file to change values found and used by cmake." + "\n" + "# If you do not want to change any of the values, simply exit the " + "editor.\n" + "# If you do want to change a value, simply edit, save, and exit " + "the editor.\n" + "# The syntax for the file is as follows:\n" + "# KEY:TYPE=VALUE\n" + "# KEY is the name of a variable in the cache.\n" + "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!." + "\n" + "# VALUE is the current value for the KEY.\n" + "\n" + "########################\n" + "# EXTERNAL cache entries\n" + "########################\n" + "\n"; /* clang-format on */ - fout << "########################\n"; - fout << "# EXTERNAL cache entries\n"; - fout << "########################\n"; - fout << "\n"; - for (auto const& i : this->Cache) { CacheEntry const& ce = i.second; cmStateEnums::CacheEntryType t = ce.Type; @@ -305,49 +295,48 @@ bool cmCacheManager::SaveCache(const std::string& path, cmMessenger* messenger) */ } else if (t != cmStateEnums::INTERNAL) { // Format is key:type=value - if (const char* help = ce.GetProperty("HELPSTRING")) { - cmCacheManager::OutputHelpString(fout, help); + if (cmProp help = ce.GetProperty("HELPSTRING")) { + cmCacheManager::OutputHelpString(fout, *help); } else { cmCacheManager::OutputHelpString(fout, "Missing description"); } cmCacheManager::OutputKey(fout, i.first); - fout << ":" << cmState::CacheEntryTypeToString(t) << "="; + fout << ':' << cmState::CacheEntryTypeToString(t) << '='; cmCacheManager::OutputValue(fout, ce.Value); - fout << "\n"; + fout << '\n'; cmCacheManager::OutputNewlineTruncationWarning(fout, i.first, ce.Value, messenger); - fout << "\n"; + fout << '\n'; } } - fout << "\n"; - fout << "########################\n"; - fout << "# INTERNAL cache entries\n"; - fout << "########################\n"; - fout << "\n"; + fout << "\n" + "########################\n" + "# INTERNAL cache entries\n" + "########################\n" + "\n"; - for (cmCacheManager::CacheIterator i = this->NewIterator(); !i.IsAtEnd(); - i.Next()) { - if (!i.Initialized()) { + for (auto const& i : this->Cache) { + if (!i.second.Initialized) { continue; } - cmStateEnums::CacheEntryType t = i.GetType(); - this->WritePropertyEntries(fout, i, messenger); + cmStateEnums::CacheEntryType t = i.second.GetType(); + this->WritePropertyEntries(fout, i.first, i.second, messenger); if (t == cmStateEnums::INTERNAL) { // Format is key:type=value - if (const char* help = i.GetProperty("HELPSTRING")) { - cmCacheManager::OutputHelpString(fout, help); + if (cmProp help = i.second.GetProperty("HELPSTRING")) { + cmCacheManager::OutputHelpString(fout, *help); } - cmCacheManager::OutputKey(fout, i.GetName()); - fout << ":" << cmState::CacheEntryTypeToString(t) << "="; - cmCacheManager::OutputValue(fout, i.GetValue()); - fout << "\n"; - cmCacheManager::OutputNewlineTruncationWarning(fout, i.GetName(), - i.GetValue(), messenger); + cmCacheManager::OutputKey(fout, i.first); + fout << ':' << cmState::CacheEntryTypeToString(t) << '='; + cmCacheManager::OutputValue(fout, i.second.GetValue()); + fout << '\n'; + cmCacheManager::OutputNewlineTruncationWarning( + fout, i.first, i.second.GetValue(), messenger); } } - fout << "\n"; + fout << '\n'; fout.Close(); std::string checkCacheFile = cmStrCat(path, "/CMakeFiles"); cmSystemTools::MakeDirectory(checkCacheFile); @@ -385,7 +374,9 @@ void cmCacheManager::OutputKey(std::ostream& fout, std::string const& key) { // support : in key name by double quoting const char* q = - (key.find(':') != std::string::npos || key.find("//") == 0) ? "\"" : ""; + (key.find(':') != std::string::npos || cmHasLiteralPrefix(key, "//")) + ? "\"" + : ""; fout << q << key << q; } @@ -430,7 +421,7 @@ void cmCacheManager::OutputHelpString(std::ostream& fout, fout << "\\n"; } oneLine = helpString.substr(pos, i - pos); - fout << oneLine << "\n"; + fout << oneLine << '\n'; pos = i; } } @@ -452,7 +443,7 @@ void cmCacheManager::OutputWarningComment(std::ostream& fout, fout << "\\n"; } oneLine = message.substr(pos, i - pos); - fout << oneLine << "\n"; + fout << oneLine << '\n'; pos = i; } } @@ -481,10 +472,7 @@ void cmCacheManager::OutputNewlineTruncationWarning(std::ostream& fout, void cmCacheManager::RemoveCacheEntry(const std::string& key) { - auto i = this->Cache.find(key); - if (i != this->Cache.end()) { - this->Cache.erase(i); - } + this->Cache.erase(key); } cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry( @@ -497,40 +485,39 @@ cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry( return nullptr; } -cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator( - const std::string& key) -{ - return { *this, key.c_str() }; -} - -cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator() +const cmCacheManager::CacheEntry* cmCacheManager::GetCacheEntry( + const std::string& key) const { - return { *this, nullptr }; + auto i = this->Cache.find(key); + if (i != this->Cache.end()) { + return &i->second; + } + return nullptr; } -const std::string* cmCacheManager::GetInitializedCacheValue( - const std::string& key) const +cmProp cmCacheManager::GetInitializedCacheValue(const std::string& key) const { - auto i = this->Cache.find(key); - if (i != this->Cache.end() && i->second.Initialized) { - return &i->second.Value; + if (auto entry = this->GetCacheEntry(key)) { + if (entry->Initialized) { + return &entry->GetValue(); + } } return nullptr; } void cmCacheManager::PrintCache(std::ostream& out) const { - out << "=================================================" << std::endl; - out << "CMakeCache Contents:" << std::endl; + out << "=================================================\n" + "CMakeCache Contents:\n"; for (auto const& i : this->Cache) { if (i.second.Type != cmStateEnums::INTERNAL) { - out << i.first << " = " << i.second.Value << std::endl; + out << i.first << " = " << i.second.Value << '\n'; } } - out << "\n\n"; - out << "To change values in the CMakeCache, " << std::endl - << "edit CMakeCache.txt in your output directory.\n"; - out << "=================================================" << std::endl; + out << "\n\n" + "To change values in the CMakeCache, \n" + "edit CMakeCache.txt in your output directory.\n" + "=================================================\n"; } void cmCacheManager::AddCacheEntry(const std::string& key, const char* value, @@ -538,12 +525,7 @@ void cmCacheManager::AddCacheEntry(const std::string& key, const char* value, cmStateEnums::CacheEntryType type) { CacheEntry& e = this->Cache[key]; - if (value) { - e.Value = value; - e.Initialized = true; - } else { - e.Value.clear(); - } + e.SetValue(value); e.Type = type; // make sure we only use unix style paths if (type == cmStateEnums::FILEPATH || type == cmStateEnums::PATH) { @@ -567,70 +549,41 @@ void cmCacheManager::AddCacheEntry(const std::string& key, const char* value, : "(This variable does not exist and should not be used)"); } -bool cmCacheManager::CacheIterator::IsAtEnd() const -{ - return this->Position == this->Container.Cache.end(); -} - -void cmCacheManager::CacheIterator::Begin() -{ - this->Position = this->Container.Cache.begin(); -} - -bool cmCacheManager::CacheIterator::Find(const std::string& key) -{ - this->Position = this->Container.Cache.find(key); - return !this->IsAtEnd(); -} - -void cmCacheManager::CacheIterator::Next() -{ - if (!this->IsAtEnd()) { - ++this->Position; - } -} - -std::vector<std::string> cmCacheManager::CacheIterator::GetPropertyList() const +void cmCacheManager::CacheEntry::SetValue(const char* value) { - return this->GetEntry().GetPropertyList(); -} - -void cmCacheManager::CacheIterator::SetValue(const char* value) -{ - if (this->IsAtEnd()) { - return; - } - CacheEntry* entry = &this->GetEntry(); if (value) { - entry->Value = value; - entry->Initialized = true; + this->Value = value; + this->Initialized = true; } else { - entry->Value.clear(); + this->Value.clear(); } } -bool cmCacheManager::CacheIterator::GetValueAsBool() const -{ - return cmIsOn(this->GetEntry().Value); -} - std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const { return this->Properties.GetKeys(); } -const char* cmCacheManager::CacheEntry::GetProperty( - const std::string& prop) const +cmProp cmCacheManager::CacheEntry::GetProperty(const std::string& prop) const { if (prop == "TYPE") { - return cmState::CacheEntryTypeToString(this->Type).c_str(); + return &cmState::CacheEntryTypeToString(this->Type); } if (prop == "VALUE") { - return this->Value.c_str(); + return &this->Value; } return this->Properties.GetPropertyValue(prop); } +bool cmCacheManager::CacheEntry::GetPropertyAsBool( + const std::string& prop) const +{ + if (cmProp value = this->GetProperty(prop)) { + return cmIsOn(*value); + } + return false; +} + void cmCacheManager::CacheEntry::SetProperty(const std::string& prop, const char* value) { @@ -643,6 +596,11 @@ void cmCacheManager::CacheEntry::SetProperty(const std::string& prop, } } +void cmCacheManager::CacheEntry::SetProperty(const std::string& p, bool v) +{ + this->SetProperty(p, v ? "ON" : "OFF"); +} + void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop, const std::string& value, bool asString) @@ -661,49 +619,3 @@ void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop, this->Properties.AppendProperty(prop, value, asString); } } - -const char* cmCacheManager::CacheIterator::GetProperty( - const std::string& prop) const -{ - if (!this->IsAtEnd()) { - return this->GetEntry().GetProperty(prop); - } - return nullptr; -} - -void cmCacheManager::CacheIterator::SetProperty(const std::string& p, - const char* v) -{ - if (!this->IsAtEnd()) { - this->GetEntry().SetProperty(p, v); - } -} - -void cmCacheManager::CacheIterator::AppendProperty(const std::string& p, - const std::string& v, - bool asString) -{ - if (!this->IsAtEnd()) { - this->GetEntry().AppendProperty(p, v, asString); - } -} - -bool cmCacheManager::CacheIterator::GetPropertyAsBool( - const std::string& prop) const -{ - if (const char* value = this->GetProperty(prop)) { - return cmIsOn(value); - } - return false; -} - -void cmCacheManager::CacheIterator::SetProperty(const std::string& p, bool v) -{ - this->SetProperty(p, v ? "ON" : "OFF"); -} - -bool cmCacheManager::CacheIterator::PropertyExists( - const std::string& prop) const -{ - return this->GetProperty(prop) != nullptr; -} diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h index d8be991cd..f0362585b 100644 --- a/Source/cmCacheManager.h +++ b/Source/cmCacheManager.h @@ -12,6 +12,7 @@ #include <utility> #include <vector> +#include "cmProperty.h" #include "cmPropertyMap.h" #include "cmStateTypes.h" @@ -25,77 +26,33 @@ class cmMessenger; */ class cmCacheManager { -public: - cmCacheManager(); - class CacheIterator; - friend class cmCacheManager::CacheIterator; - -private: - struct CacheEntry + class CacheEntry { - std::string Value; - cmStateEnums::CacheEntryType Type = cmStateEnums::UNINITIALIZED; - cmPropertyMap Properties; - 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 std::string& value, - bool asString = false); - bool Initialized = false; - }; + friend class cmCacheManager; -public: - class CacheIterator - { public: - void Begin(); - bool Find(const std::string&); - bool IsAtEnd() const; - void Next(); - std::string GetName() const { return this->Position->first; } + const std::string& GetValue() const { return this->Value; } + void SetValue(const char*); + + cmStateEnums::CacheEntryType GetType() const { return this->Type; } + void SetType(cmStateEnums::CacheEntryType ty) { this->Type = ty; } + std::vector<std::string> GetPropertyList() const; - const char* GetProperty(const std::string&) const; - bool GetPropertyAsBool(const std::string&) const; - bool PropertyExists(const std::string&) const; + cmProp GetProperty(const std::string& property) const; + bool GetPropertyAsBool(const std::string& property) const; void SetProperty(const std::string& property, const char* value); + void SetProperty(const std::string& property, bool value); void AppendProperty(const std::string& property, const std::string& value, bool asString = false); - void SetProperty(const std::string& property, bool value); - const std::string& GetValue() const { return this->GetEntry().Value; } - bool GetValueAsBool() const; - void SetValue(const char*); - cmStateEnums::CacheEntryType GetType() const - { - return this->GetEntry().Type; - } - void SetType(cmStateEnums::CacheEntryType ty) - { - this->GetEntry().Type = ty; - } - bool Initialized() { return this->GetEntry().Initialized; } - cmCacheManager& Container; - std::map<std::string, CacheEntry>::iterator Position; - CacheIterator(cmCacheManager& cm) - : Container(cm) - { - this->Begin(); - } - CacheIterator(cmCacheManager& cm, const char* key) - : Container(cm) - { - if (key) { - this->Find(key); - } - } private: - CacheEntry const& GetEntry() const { return this->Position->second; } - CacheEntry& GetEntry() { return this->Position->second; } + std::string Value; + cmStateEnums::CacheEntryType Type = cmStateEnums::UNINITIALIZED; + cmPropertyMap Properties; + bool Initialized = false; }; - //! return an iterator to iterate through the cache map - cmCacheManager::CacheIterator NewIterator() { return { *this }; } - +public: //! Load a cache for given makefile. Loads from path/CMakeCache.txt. bool LoadCache(const std::string& path, bool internal, std::set<std::string>& excludes, @@ -110,67 +67,82 @@ public: //! Print the cache to a stream void PrintCache(std::ostream&) const; - //! Get the iterator for an entry with a given key. - cmCacheManager::CacheIterator GetCacheIterator(const std::string& key); - cmCacheManager::CacheIterator GetCacheIterator(); - - //! Remove an entry from the cache - void RemoveCacheEntry(const std::string& key); + //! Get a value from the cache given a key + cmProp GetInitializedCacheValue(const std::string& key) const; - //! Get the number of entries in the cache - int GetSize() { return static_cast<int>(this->Cache.size()); } + cmProp GetCacheEntryValue(const std::string& key) const + { + if (auto entry = this->GetCacheEntry(key)) { + return &entry->GetValue(); + } + return nullptr; + } - //! Get a value from the cache given a key - const std::string* GetInitializedCacheValue(const std::string& key) const; + void SetCacheEntryValue(std::string const& key, std::string const& value) + { + if (auto entry = this->GetCacheEntry(key)) { + entry->SetValue(value.c_str()); + } + } - const char* GetCacheEntryValue(const std::string& key) + cmStateEnums::CacheEntryType GetCacheEntryType(std::string const& key) const { - cmCacheManager::CacheIterator it = this->GetCacheIterator(key); - if (it.IsAtEnd()) { - return nullptr; + if (auto entry = this->GetCacheEntry(key)) { + return entry->GetType(); } - return it.GetValue().c_str(); + return cmStateEnums::UNINITIALIZED; } - const char* GetCacheEntryProperty(std::string const& key, - std::string const& propName) + std::vector<std::string> GetCacheEntryPropertyList( + std::string const& key) const { - return this->GetCacheIterator(key).GetProperty(propName); + if (auto entry = this->GetCacheEntry(key)) { + return entry->GetPropertyList(); + } + return {}; } - cmStateEnums::CacheEntryType GetCacheEntryType(std::string const& key) + cmProp GetCacheEntryProperty(std::string const& key, + std::string const& propName) const { - return this->GetCacheIterator(key).GetType(); + if (auto entry = this->GetCacheEntry(key)) { + return entry->GetProperty(propName); + } + return nullptr; } bool GetCacheEntryPropertyAsBool(std::string const& key, - std::string const& propName) + std::string const& propName) const { - return this->GetCacheIterator(key).GetPropertyAsBool(propName); + if (auto entry = this->GetCacheEntry(key)) { + return entry->GetPropertyAsBool(propName); + } + return false; } void SetCacheEntryProperty(std::string const& key, std::string const& propName, std::string const& value) { - this->GetCacheIterator(key).SetProperty(propName, value.c_str()); + if (auto entry = this->GetCacheEntry(key)) { + entry->SetProperty(propName, value.c_str()); + } } void SetCacheEntryBoolProperty(std::string const& key, std::string const& propName, bool value) { - this->GetCacheIterator(key).SetProperty(propName, value); - } - - void SetCacheEntryValue(std::string const& key, std::string const& value) - { - this->GetCacheIterator(key).SetValue(value.c_str()); + if (auto entry = this->GetCacheEntry(key)) { + entry->SetProperty(propName, value); + } } void RemoveCacheEntryProperty(std::string const& key, std::string const& propName) { - this->GetCacheIterator(key).SetProperty(propName, nullptr); + if (auto entry = this->GetCacheEntry(key)) { + entry->SetProperty(propName, nullptr); + } } void AppendCacheEntryProperty(std::string const& key, @@ -178,16 +150,17 @@ public: std::string const& value, bool asString = false) { - this->GetCacheIterator(key).AppendProperty(propName, value, asString); + if (auto entry = this->GetCacheEntry(key)) { + entry->AppendProperty(propName, value, asString); + } } - std::vector<std::string> GetCacheEntryKeys() + std::vector<std::string> GetCacheEntryKeys() const { std::vector<std::string> definitions; - definitions.reserve(this->GetSize()); - cmCacheManager::CacheIterator cit = this->GetCacheIterator(); - for (cit.Begin(); !cit.IsAtEnd(); cit.Next()) { - definitions.push_back(cit.GetName()); + definitions.reserve(this->Cache.size()); + for (auto const& i : this->Cache) { + definitions.push_back(i.first); } return definitions; } @@ -196,23 +169,22 @@ public: unsigned int GetCacheMajorVersion() const { return this->CacheMajorVersion; } unsigned int GetCacheMinorVersion() const { return this->CacheMinorVersion; } -protected: //! Add an entry into the cache void AddCacheEntry(const std::string& key, const char* value, const char* helpString, cmStateEnums::CacheEntryType type); + //! Remove an entry from the cache + void RemoveCacheEntry(const std::string& key); + +private: //! Get a cache entry object for a key CacheEntry* GetCacheEntry(const std::string& key); + const CacheEntry* GetCacheEntry(const std::string& key) const; + //! Clean out the CMakeFiles directory if no CMakeCache.txt void CleanCMakeFiles(const std::string& path); - // Cache version info - unsigned int CacheMajorVersion; - unsigned int CacheMinorVersion; - -private: - using CacheEntryMap = std::map<std::string, CacheEntry>; static void OutputHelpString(std::ostream& fout, const std::string& helpString); static void OutputWarningComment(std::ostream& fout, @@ -228,15 +200,15 @@ private: std::string const& value); static const char* PersistentProperties[]; - bool ReadPropertyEntry(std::string const& key, CacheEntry& e); - void WritePropertyEntries(std::ostream& os, CacheIterator i, - cmMessenger* messenger); - - CacheEntryMap Cache; - // Only cmake and cmState should be able to add cache values - // the commands should never use the cmCacheManager directly - friend class cmState; // allow access to add cache values - friend class cmake; // allow access to add cache values + bool ReadPropertyEntry(const std::string& key, const CacheEntry& e); + void WritePropertyEntries(std::ostream& os, const std::string& entryKey, + const CacheEntry& e, cmMessenger* messenger) const; + + std::map<std::string, CacheEntry> Cache; + + // Cache version info + unsigned int CacheMajorVersion = 0; + unsigned int CacheMinorVersion = 0; }; #endif diff --git a/Source/cmCallVisualStudioMacro.cxx b/Source/cmCallVisualStudioMacro.cxx index 9e152ff80..94b6e186a 100644 --- a/Source/cmCallVisualStudioMacro.cxx +++ b/Source/cmCallVisualStudioMacro.cxx @@ -43,8 +43,7 @@ static bool LogErrorsAsMessages; if (LogErrorsAsMessages) { \ std::ostringstream _hresult_oss; \ _hresult_oss.flags(std::ios::hex); \ - _hresult_oss << context << " failed HRESULT, hr = 0x" << hr \ - << std::endl; \ + _hresult_oss << context << " failed HRESULT, hr = 0x" << hr << '\n'; \ _hresult_oss.flags(std::ios::dec); \ _hresult_oss << __FILE__ << "(" << __LINE__ << ")"; \ cmSystemTools::Message(_hresult_oss.str()); \ @@ -98,32 +97,37 @@ HRESULT InstanceCallMacro(IDispatch* vsIDE, const std::string& macro, DISPATCH_METHOD, ¶ms, &result, &excep, &arg); std::ostringstream oss; - oss << std::endl; - oss << "Invoke(ExecuteCommand)" << std::endl; - oss << " Macro: " << macro << std::endl; - oss << " Args: " << args << std::endl; + /* clang-format off */ + oss << "\nInvoke(ExecuteCommand)\n" + " Macro: " << macro << "\n" + " Args: " << args << '\n'; + /* clang-format on */ if (DISP_E_EXCEPTION == hr) { - oss << "DISP_E_EXCEPTION EXCEPINFO:" << excep.wCode << std::endl; - oss << " wCode: " << excep.wCode << std::endl; - oss << " wReserved: " << excep.wReserved << std::endl; + /* clang-format off */ + oss << "DISP_E_EXCEPTION EXCEPINFO:" << excep.wCode << "\n" + " wCode: " << excep.wCode << "\n" + " wReserved: " << excep.wReserved << '\n'; + /* clang-format on */ if (excep.bstrSource) { oss << " bstrSource: " << (const char*)(_bstr_t)excep.bstrSource - << std::endl; + << '\n'; } if (excep.bstrDescription) { oss << " bstrDescription: " - << (const char*)(_bstr_t)excep.bstrDescription << std::endl; + << (const char*)(_bstr_t)excep.bstrDescription << '\n'; } if (excep.bstrHelpFile) { oss << " bstrHelpFile: " << (const char*)(_bstr_t)excep.bstrHelpFile - << std::endl; + << '\n'; } - oss << " dwHelpContext: " << excep.dwHelpContext << std::endl; - oss << " pvReserved: " << excep.pvReserved << std::endl; - oss << " pfnDeferredFillIn: " - << reinterpret_cast<void*>(excep.pfnDeferredFillIn) << std::endl; - oss << " scode: " << excep.scode << std::endl; + /* clang-format off */ + oss << " dwHelpContext: " << excep.dwHelpContext << "\n" + " pvReserved: " << excep.pvReserved << "\n" + " pfnDeferredFillIn: " + << reinterpret_cast<void*>(excep.pfnDeferredFillIn) << "\n" + " scode: " << excep.scode << '\n'; + /* clang-format on */ } std::string exstr(oss.str()); diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index 613ae06d1..87eb91ce1 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -5,9 +5,13 @@ #include <cstring> #include <iostream> #include <sstream> +#include <utility> + +#include <cm/memory> #include "cmCommandArgumentLexer.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -40,10 +44,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( @@ -66,8 +70,7 @@ const char* cmCommandArgumentParserHelper::ExpandSpecialVariable( return ""; } if (strcmp(key, "CACHE") == 0) { - if (const std::string* c = - this->Makefile->GetState()->GetInitializedCacheValue(var)) { + if (cmProp c = this->Makefile->GetState()->GetInitializedCacheValue(var)) { if (this->EscapeQuotes) { return this->AddString(cmEscapeQuotes(*c)); } @@ -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 25e689224..b46edcbea 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 896b6a98d..c94f12886 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -92,6 +92,7 @@ # include "cmAuxSourceDirectoryCommand.h" # include "cmBuildNameCommand.h" # include "cmCMakeHostSystemInformationCommand.h" +# include "cmCMakeLanguageCommand.h" # include "cmExportCommand.h" # include "cmExportLibraryDependenciesCommand.h" # include "cmFLTKWrapUICommand.h" @@ -198,6 +199,7 @@ void GetScriptingCommands(cmState* state) #if !defined(CMAKE_BOOTSTRAP) state->AddBuiltinCommand("cmake_host_system_information", cmCMakeHostSystemInformationCommand); + state->AddBuiltinCommand("cmake_language", cmCMakeLanguageCommand); state->AddBuiltinCommand("load_cache", cmLoadCacheCommand); state->AddBuiltinCommand("remove", cmRemoveCommand); state->AddBuiltinCommand("variable_watch", cmVariableWatchCommand); diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 033cb6039..051eff6f7 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -14,6 +14,7 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmSourceFile.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -73,11 +74,12 @@ void cmCommonTargetGenerator::AddModuleDefinitionFlag( void cmCommonTargetGenerator::AppendFortranFormatFlags( std::string& flags, cmSourceFile const& source) { - const char* srcfmt = source.GetProperty("Fortran_FORMAT"); + const std::string srcfmt = source.GetSafeProperty("Fortran_FORMAT"); cmOutputConverter::FortranFormat format = cmOutputConverter::GetFortranFormat(srcfmt); if (format == cmOutputConverter::FortranFormatNone) { - const char* tgtfmt = this->GeneratorTarget->GetProperty("Fortran_FORMAT"); + std::string const& tgtfmt = + this->GeneratorTarget->GetSafeProperty("Fortran_FORMAT"); format = cmOutputConverter::GetFortranFormat(tgtfmt); } const char* var = nullptr; @@ -97,18 +99,49 @@ void cmCommonTargetGenerator::AppendFortranFormatFlags( } } +void cmCommonTargetGenerator::AppendFortranPreprocessFlags( + std::string& flags, cmSourceFile const& source) +{ + const std::string srcpp = source.GetSafeProperty("Fortran_PREPROCESS"); + cmOutputConverter::FortranPreprocess preprocess = + cmOutputConverter::GetFortranPreprocess(srcpp); + if (preprocess == cmOutputConverter::FortranPreprocess::Unset) { + std::string const& tgtpp = + this->GeneratorTarget->GetSafeProperty("Fortran_PREPROCESS"); + preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp); + } + const char* var = nullptr; + switch (preprocess) { + case cmOutputConverter::FortranPreprocess::Needed: + var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON"; + break; + case cmOutputConverter::FortranPreprocess::NotNeeded: + var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF"; + break; + default: + break; + } + if (var) { + this->LocalCommonGenerator->AppendCompileOptions( + flags, this->Makefile->GetSafeDefinition(var)); + } +} + std::string cmCommonTargetGenerator::GetFlags(const std::string& l, - const std::string& config) + const std::string& config, + const std::string& arch) { - auto i = this->Configs[config].FlagsByLanguage.find(l); - if (i == this->Configs[config].FlagsByLanguage.end()) { + const std::string key = config + arch; + + auto i = this->Configs[key].FlagsByLanguage.find(l); + if (i == this->Configs[key].FlagsByLanguage.end()) { std::string flags; this->LocalCommonGenerator->GetTargetCompileFlags(this->GeneratorTarget, - config, l, flags); + config, l, flags, arch); ByLanguageMap::value_type entry(l, flags); - i = this->Configs[config].FlagsByLanguage.insert(entry).first; + i = this->Configs[key].FlagsByLanguage.insert(entry).first; } return i->second; } @@ -221,9 +254,9 @@ std::string cmCommonTargetGenerator::GetAIXExports(std::string const&) { std::string aixExports; if (this->GeneratorTarget->Target->IsAIX()) { - if (const char* exportAll = + if (cmProp exportAll = this->GeneratorTarget->GetProperty("AIX_EXPORT_ALL_SYMBOLS")) { - if (cmIsOff(exportAll)) { + if (cmIsOff(*exportAll)) { aixExports = "-n"; } } diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index b40a2edad..c3c3a3a88 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -45,13 +45,17 @@ protected: void AppendFortranFormatFlags(std::string& flags, cmSourceFile const& source); + void AppendFortranPreprocessFlags(std::string& flags, + cmSourceFile const& source); + virtual void AddIncludeFlags(std::string& flags, std::string const& lang, const std::string& config) = 0; void AppendOSXVerFlag(std::string& flags, const std::string& lang, const char* name, bool so); - std::string GetFlags(const std::string& l, const std::string& config); + std::string GetFlags(const std::string& l, const std::string& config, + const std::string& arch = std::string()); 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); diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 11570d644..4c5f57d05 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -9,10 +9,9 @@ #include <utility> #include <cm/memory> +#include <cmext/algorithm> -#include "cmAlgorithms.h" #include "cmComputeLinkDepends.h" -#include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmListFileCache.h" @@ -22,6 +21,7 @@ #include "cmOrderDirectories.h" #include "cmOutputConverter.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -514,8 +514,8 @@ bool cmComputeLinkInformation::Compute() // Restore the target link type so the correct system runtime // libraries are found. - const char* lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC"); - if (cmIsOn(lss)) { + cmProp lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC"); + if (lss && cmIsOn(*lss)) { this->SetCurrentLinkType(LinkStatic); } else { this->SetCurrentLinkType(this->StartLinkType); @@ -587,33 +587,18 @@ void cmComputeLinkInformation::AddImplicitLinkInfo() } void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang) -{ // Add the lang runtime library flags. This is activated by the presence - // of a default selection whether or not it is overridden by a property. - std::string defaultVar = - cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT"); - 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); - } - } +{ + std::string const& runtimeLibrary = + this->Target->GetRuntimeLinkLibrary(lang, this->Config); + if (runtimeLibrary.empty()) { + return; + } + if (const char* runtimeLinkOptions = this->Makefile->GetDefinition( + "CMAKE_" + lang + "_RUNTIME_LIBRARY_LINK_OPTIONS_" + runtimeLibrary)) { + std::vector<std::string> libsVec = cmExpandedList(runtimeLinkOptions); + for (std::string const& i : libsVec) { + if (!cm::contains(this->ImplicitLinkLibs, i)) { + this->AddItem(i, nullptr); } } } @@ -627,7 +612,7 @@ void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang) if (const char* libs = this->Makefile->GetDefinition(libVar)) { std::vector<std::string> libsVec = cmExpandedList(libs); for (std::string const& i : libsVec) { - if (!cmContains(this->ImplicitLinkLibs, i)) { + if (!cm::contains(this->ImplicitLinkLibs, i)) { this->AddItem(i, nullptr); } } @@ -855,8 +840,8 @@ void cmComputeLinkInformation::ComputeLinkTypeInfo() } // Lookup the starting link type from the target (linked statically?). - const char* lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC"); - this->StartLinkType = cmIsOn(lss) ? LinkStatic : LinkShared; + cmProp lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC"); + this->StartLinkType = (lss && cmIsOn(*lss)) ? LinkStatic : LinkShared; this->CurrentLinkType = this->StartLinkType; } @@ -998,15 +983,16 @@ std::string cmComputeLinkInformation::CreateExtensionRegex( std::string cmComputeLinkInformation::NoCaseExpression(const char* str) { std::string ret; + ret.reserve(strlen(str) * 4); const char* s = str; while (*s) { if (*s == '.') { ret += *s; } else { - ret += "["; + ret += '['; ret += static_cast<char>(tolower(*s)); ret += static_cast<char>(toupper(*s)); - ret += "]"; + ret += ']'; } s++; } @@ -1063,8 +1049,8 @@ void cmComputeLinkInformation::AddTargetItem(BT<std::string> const& item, // For compatibility with CMake 2.4 include the item's directory in // the linker search path. if (this->OldLinkDirMode && !target->IsFrameworkOnApple() && - !cmContains(this->OldLinkDirMask, - cmSystemTools::GetFilenamePath(item.Value))) { + !cm::contains(this->OldLinkDirMask, + cmSystemTools::GetFilenamePath(item.Value))) { this->OldLinkDirItems.push_back(item.Value); } @@ -1117,8 +1103,8 @@ void cmComputeLinkInformation::AddFullItem(BT<std::string> const& item) // For compatibility with CMake 2.4 include the item's directory in // the linker search path. if (this->OldLinkDirMode && - !cmContains(this->OldLinkDirMask, - cmSystemTools::GetFilenamePath(item.Value))) { + !cm::contains(this->OldLinkDirMask, + cmSystemTools::GetFilenamePath(item.Value))) { this->OldLinkDirItems.push_back(item.Value); } @@ -1137,7 +1123,7 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) // Check if this item is in an implicit link directory. std::string dir = cmSystemTools::GetFilenamePath(item); - if (!cmContains(this->ImplicitLinkDirs, dir)) { + if (!cm::contains(this->ImplicitLinkDirs, dir)) { // Only libraries in implicit link directories are converted to // pathless items. return false; @@ -1200,7 +1186,8 @@ void cmComputeLinkInformation::AddUserItem(BT<std::string> const& item, // CMP0003 so put it in OldUserFlagItems, if it is not a -l // or -Wl,-l (-framework -pthread), then allow it without a // CMP0003 as -L will not affect those other linker flags - if (item.Value.find("-l") == 0 || item.Value.find("-Wl,-l") == 0) { + if (cmHasLiteralPrefix(item.Value, "-l") || + cmHasLiteralPrefix(item.Value, "-Wl,-l")) { // This is a linker option provided by the user. this->OldUserFlagItems.push_back(item.Value); } @@ -1344,18 +1331,13 @@ void cmComputeLinkInformation::ComputeFrameworkInfo() std::vector<std::string> implicitDirVec; // Get platform-wide implicit directories. - if (const char* implicitLinks = this->Makefile->GetDefinition( - "CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES")) { - cmExpandList(implicitLinks, implicitDirVec); - } + this->Makefile->GetDefExpandList( + "CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", implicitDirVec); // Get language-specific implicit directories. std::string implicitDirVar = cmStrCat( "CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES"); - if (const char* implicitDirs = - this->Makefile->GetDefinition(implicitDirVar)) { - cmExpandList(implicitDirs, implicitDirVec); - } + this->Makefile->GetDefExpandList(implicitDirVar, implicitDirVec); this->FrameworkPathsEmmitted.insert(implicitDirVec.begin(), implicitDirVec.end()); @@ -1439,7 +1421,6 @@ void cmComputeLinkInformation::HandleBadFullItem(std::string const& item, } case cmPolicies::OLD: // OLD behavior does not warn. - break; case cmPolicies::NEW: // NEW behavior will not get here. break; @@ -1569,10 +1550,8 @@ void cmComputeLinkInformation::LoadImplicitLinkInfo() std::vector<std::string> implicitDirVec; // Get platform-wide implicit directories. - if (const char* implicitLinks = (this->Makefile->GetDefinition( - "CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES"))) { - cmExpandList(implicitLinks, implicitDirVec); - } + this->Makefile->GetDefExpandList("CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES", + implicitDirVec); // Append library architecture to all implicit platform directories // and add them to the set @@ -1586,10 +1565,7 @@ void cmComputeLinkInformation::LoadImplicitLinkInfo() // Get language-specific implicit directories. std::string implicitDirVar = cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_DIRECTORIES"); - if (const char* implicitDirs = - this->Makefile->GetDefinition(implicitDirVar)) { - cmExpandList(implicitDirs, implicitDirVec); - } + this->Makefile->GetDefExpandList(implicitDirVar, implicitDirVec); // Store implicit link directories. this->ImplicitLinkDirs.insert(implicitDirVec.begin(), implicitDirVec.end()); @@ -1598,10 +1574,7 @@ void cmComputeLinkInformation::LoadImplicitLinkInfo() std::vector<std::string> implicitLibVec; std::string implicitLibVar = cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_LIBRARIES"); - if (const char* implicitLibs = - this->Makefile->GetDefinition(implicitLibVar)) { - cmExpandList(implicitLibs, implicitLibVec); - } + this->Makefile->GetDefExpandList(implicitLibVar, implicitLibVec); // Store implicit link libraries. for (std::string const& item : implicitLibVec) { @@ -1613,10 +1586,8 @@ void cmComputeLinkInformation::LoadImplicitLinkInfo() } // Get platform specific rpath link directories - if (const char* rpathDirs = - (this->Makefile->GetDefinition("CMAKE_PLATFORM_RUNTIME_PATH"))) { - cmExpandList(rpathDirs, this->RuntimeLinkDirs); - } + this->Makefile->GetDefExpandList("CMAKE_PLATFORM_RUNTIME_PATH", + this->RuntimeLinkDirs); } std::vector<std::string> const& @@ -1796,11 +1767,11 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, // support or if using the link path as an rpath. if (use_build_rpath) { std::string d = ri; - if (!rootPath.empty() && d.find(rootPath) == 0) { - d = d.substr(rootPath.size()); - } else if (stagePath && *stagePath && d.find(stagePath) == 0) { - std::string suffix = d.substr(strlen(stagePath)); - d = cmStrCat(installPrefix, '/', suffix); + if (!rootPath.empty() && cmHasPrefix(d, rootPath)) { + d.erase(0, rootPath.size()); + } else if (stagePath && *stagePath && cmHasPrefix(d, stagePath)) { + d.erase(0, strlen(stagePath)); + d = cmStrCat(installPrefix, '/', d); cmSystemTools::ConvertToUnixSlashes(d); } else if (use_relative_build_rpath) { // If expansion of the $ORIGIN token is supported and permitted per @@ -1827,11 +1798,11 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, !cmSystemTools::IsSubDirectory(ri, topSourceDir) && !cmSystemTools::IsSubDirectory(ri, topBinaryDir)) { std::string d = ri; - if (!rootPath.empty() && d.find(rootPath) == 0) { - d = d.substr(rootPath.size()); - } else if (stagePath && *stagePath && d.find(stagePath) == 0) { - std::string suffix = d.substr(strlen(stagePath)); - d = cmStrCat(installPrefix, '/', suffix); + if (!rootPath.empty() && cmHasPrefix(d, rootPath)) { + d.erase(0, rootPath.size()); + } else if (stagePath && *stagePath && cmHasPrefix(d, stagePath)) { + d.erase(0, strlen(stagePath)); + d = cmStrCat(installPrefix, '/', d); cmSystemTools::ConvertToUnixSlashes(d); } if (emitted.insert(d).second) { diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index a98a608e4..41f534635 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -198,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) { @@ -222,19 +236,6 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) } } } - - 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); - } - } } } diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index fda687fd3..7a3a3e8ac 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -13,7 +13,6 @@ #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmState.h" @@ -494,12 +493,12 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&, if (this->IsKeyword(keyDEFINED, *arg) && argP1 != newArgs.end()) { size_t argP1len = argP1->GetValue().size(); bool bdef = false; - if (argP1len > 4 && argP1->GetValue().substr(0, 4) == "ENV{" && + if (argP1len > 4 && cmHasLiteralPrefix(argP1->GetValue(), "ENV{") && argP1->GetValue().operator[](argP1len - 1) == '}') { std::string env = argP1->GetValue().substr(4, argP1len - 5); bdef = cmSystemTools::HasEnv(env); } else if (argP1len > 6 && - argP1->GetValue().substr(0, 6) == "CACHE{" && + cmHasLiteralPrefix(argP1->GetValue(), "CACHE{") && argP1->GetValue().operator[](argP1len - 1) == '}') { std::string cache = argP1->GetValue().substr(6, argP1len - 7); bdef = @@ -673,7 +672,7 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, if (def2) { std::vector<std::string> list = cmExpandedList(def2, true); - result = cmContains(list, def); + result = cm::contains(list, def); } this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); diff --git a/Source/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx index 8767386cf..5b3045db1 100644 --- a/Source/cmConfigureFileCommand.cxx +++ b/Source/cmConfigureFileCommand.cxx @@ -2,6 +2,11 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmConfigureFileCommand.h" +#include <set> + +#include <cm/string_view> +#include <cmext/string_view> + #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -56,6 +61,18 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args, bool copyOnly = false; bool escapeQuotes = false; + static std::set<cm::string_view> noopOptions = { + /* Legacy. */ + "IMMEDIATE"_s, + /* Handled by NewLineStyle member. */ + "NEWLINE_STYLE"_s, + "LF"_s, + "UNIX"_s, + "CRLF"_s, + "WIN32"_s, + "DOS"_s, + }; + std::string unknown_args; bool atOnly = false; for (unsigned int i = 2; i < args.size(); ++i) { @@ -70,12 +87,8 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args, escapeQuotes = true; } else if (args[i] == "@ONLY") { atOnly = true; - } else if (args[i] == "IMMEDIATE") { - /* Ignore legacy option. */ - } 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 if (noopOptions.find(args[i]) != noopOptions.end()) { + /* Ignore no-op options. */ } else { unknown_args += " "; unknown_args += args[i]; diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx index 884e31432..e4d0cf11b 100644 --- a/Source/cmConnection.cxx +++ b/Source/cmConnection.cxx @@ -5,7 +5,7 @@ #include <cassert> #include <cstring> -#include "cm_uv.h" +#include <cm3p/uv.h> #include "cmServer.h" @@ -20,8 +20,13 @@ void cmEventBasedConnection::on_alloc_buffer(uv_handle_t* handle, uv_buf_t* buf) { (void)(handle); +#ifndef __clang_analyzer__ char* rawBuffer = new char[suggested_size]; *buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size)); +#else + (void)(suggested_size); + (void)(buf); +#endif /* __clang_analyzer__ */ } void cmEventBasedConnection::on_read(uv_stream_t* stream, ssize_t nread, @@ -76,6 +81,7 @@ void cmEventBasedConnection::WriteData(const std::string& _data) assert(uv_thread_equal(&curr_thread_id, &this->Server->ServeThreadId)); #endif +#ifndef __clang_analyzer__ auto data = _data; assert(this->WriteStream.get()); if (BufferStrategy) { @@ -90,6 +96,9 @@ void cmEventBasedConnection::WriteData(const std::string& _data) memcpy(req->buf.base, data.c_str(), ds); uv_write(reinterpret_cast<uv_write_t*>(req), this->WriteStream, &req->buf, 1, on_write); +#else + (void)(_data); +#endif /* __clang_analyzer__ */ } void cmEventBasedConnection::ReadData(const std::string& data) diff --git a/Source/cmConnection.h b/Source/cmConnection.h index 7bb249404..5335a7f3c 100644 --- a/Source/cmConnection.h +++ b/Source/cmConnection.h @@ -9,7 +9,7 @@ #include <memory> #include <string> -#include "cm_uv.h" +#include <cm3p/uv.h> #include "cmUVHandlePtr.h" diff --git a/Source/cmConvertMSBuildXMLToJSON.py b/Source/cmConvertMSBuildXMLToJSON.py index 02074ba65..2be3781c5 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 73f099b98..8550d04da 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -8,9 +8,9 @@ #include <sstream> #include <utility> -#include "cmsys/Directory.hxx" +#include <cmext/string_view> -#include "cm_static_string_view.hxx" +#include "cmsys/Directory.hxx" #include "cmExportTryCompileFileGenerator.h" #include "cmGlobalGenerator.h" @@ -40,6 +40,10 @@ static std::string const kCMAKE_CXX_LINK_NO_PIE_SUPPORTED = "CMAKE_CXX_LINK_NO_PIE_SUPPORTED"; static std::string const kCMAKE_CXX_LINK_PIE_SUPPORTED = "CMAKE_CXX_LINK_PIE_SUPPORTED"; +static std::string const kCMAKE_CUDA_ARCHITECTURES = + "CMAKE_CUDA_ARCHITECTURES"; +static std::string const kCMAKE_CUDA_COMPILER_TARGET = + "CMAKE_CUDA_COMPILER_TARGET"; static std::string const kCMAKE_CUDA_RUNTIME_LIBRARY = "CMAKE_CUDA_RUNTIME_LIBRARY"; static std::string const kCMAKE_ENABLE_EXPORTS = "CMAKE_ENABLE_EXPORTS"; @@ -103,29 +107,23 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, this->SrcFileSignature = true; cmStateEnums::TargetType targetType = cmStateEnums::EXECUTABLE; - const char* tt = - this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE"); - if (!isTryRun && tt && *tt) { - if (strcmp(tt, cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) == - 0) { + const std::string* tt = + this->Makefile->GetDef("CMAKE_TRY_COMPILE_TARGET_TYPE"); + if (!isTryRun && tt && !tt->empty()) { + if (*tt == cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) { targetType = cmStateEnums::EXECUTABLE; - } else if (strcmp(tt, - cmState::GetTargetTypeName( - cmStateEnums::STATIC_LIBRARY)) == 0) { + } else if (*tt == + cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY)) { targetType = cmStateEnums::STATIC_LIBRARY; } else { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, - std::string("Invalid value '") + tt + - "' for " - "CMAKE_TRY_COMPILE_TARGET_TYPE. Only " - "'" + - cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE) + - "' and " - "'" + - cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY) + - "' " - "are allowed."); + cmStrCat("Invalid value '", *tt, + "' for CMAKE_TRY_COMPILE_TARGET_TYPE. Only '", + cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE), + "' and '", + cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY), + "' are allowed.")); return -1; } } @@ -298,12 +296,10 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, default: this->Makefile->IssueMessage( MessageType::FATAL_ERROR, - "Only libraries may be used as try_compile or try_run IMPORTED " - "LINK_LIBRARIES. Got " + - std::string(tgt->GetName()) + - " of " - "type " + - cmState::GetTargetTypeName(tgt->GetType()) + "."); + cmStrCat("Only libraries may be used as try_compile or try_run " + "IMPORTED LINK_LIBRARIES. Got ", + tgt->GetName(), " of type ", + cmState::GetTargetTypeName(tgt->GetType()), ".")); return -1; } if (tgt->IsImported()) { @@ -571,6 +567,14 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, *msvcRuntimeLibraryDefault ? "NEW" : "OLD"); } + /* Set CUDA architectures policy to match outer project. */ + if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0104) != + cmPolicies::NEW && + testLangs.find("CUDA") != testLangs.end() && + this->Makefile->GetSafeDefinition(kCMAKE_CUDA_ARCHITECTURES).empty()) { + fprintf(fout, "cmake_policy(SET CMP0104 OLD)\n"); + } + std::string projectLangs; for (std::string const& li : testLangs) { projectLangs += " " + li; @@ -721,6 +725,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, vars.insert(kCMAKE_C_COMPILER_TARGET); vars.insert(kCMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN); vars.insert(kCMAKE_CXX_COMPILER_TARGET); + vars.insert(kCMAKE_CUDA_ARCHITECTURES); + vars.insert(kCMAKE_CUDA_COMPILER_TARGET); vars.insert(kCMAKE_CUDA_RUNTIME_LIBRARY); vars.insert(kCMAKE_ENABLE_EXPORTS); vars.insert(kCMAKE_LINK_SEARCH_END_STATIC); @@ -1044,7 +1050,9 @@ void cmCoreTryCompile::CleanupFiles(std::string const& binDir) std::set<std::string> deletedFiles; for (unsigned long i = 0; i < dir.GetNumberOfFiles(); ++i) { const char* fileName = dir.GetFile(i); - if (strcmp(fileName, ".") != 0 && strcmp(fileName, "..") != 0) { + if (strcmp(fileName, ".") != 0 && strcmp(fileName, "..") != 0 && + // Do not delete NFS temporary files. + !cmHasPrefix(fileName, ".nfs")) { if (deletedFiles.insert(fileName).second) { std::string const fullPath = std::string(binDir).append("/").append(fileName); diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index dc7d939c9..b1e63ba65 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -4,10 +4,10 @@ #include <cm/memory> -#include "cmsys/FStream.hxx" +#include <cm3p/kwiml/int.h> +#include <cm3p/rhash.h> -#include "cm_kwiml.h" -#include "cm_rhash.h" +#include "cmsys/FStream.hxx" static unsigned int const cmCryptoHashAlgoToId[] = { /* clang-format needs this comment to break after the opening brace */ diff --git a/Source/cmCurl.h b/Source/cmCurl.h index cb73ce631..7bd036e5d 100644 --- a/Source/cmCurl.h +++ b/Source/cmCurl.h @@ -7,7 +7,7 @@ #include <string> -#include "cm_curl.h" +#include <cm3p/curl/curl.h> std::string cmCurlSetCAInfo(::CURL* curl, const char* cafile = nullptr); std::string cmCurlSetNETRCOption(::CURL* curl, const std::string& netrc_level, diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index 0dd8722cf..149f5e99e 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -11,7 +11,8 @@ cmCustomCommand::cmCustomCommand(std::vector<std::string> outputs, std::vector<std::string> depends, cmCustomCommandLines commandLines, cmListFileBacktrace lfbt, const char* comment, - const char* workingDirectory) + const char* workingDirectory, + bool stdPipesUTF8) : Outputs(std::move(outputs)) , Byproducts(std::move(byproducts)) , Depends(std::move(depends)) @@ -20,6 +21,7 @@ cmCustomCommand::cmCustomCommand(std::vector<std::string> outputs, , Comment(comment ? comment : "") , WorkingDirectory(workingDirectory ? workingDirectory : "") , HaveComment(comment != nullptr) + , StdPipesUTF8(stdPipesUTF8) { } diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index d300fa569..aa572ad81 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -30,7 +30,8 @@ public: std::vector<std::string> byproducts, std::vector<std::string> depends, cmCustomCommandLines commandLines, cmListFileBacktrace lfbt, - const char* comment, const char* workingDirectory); + const char* comment, const char* workingDirectory, + bool stdPipesUTF8); /** Get the output file produced by the command. */ const std::vector<std::string>& GetOutputs() const; @@ -53,6 +54,9 @@ public: /** Get the comment string for the command. */ const char* GetComment() const; + /** Get a value indicating if the command uses UTF-8 output pipes. */ + bool GetStdPipesUTF8() const { return this->StdPipesUTF8; } + /** Append to the list of command lines. */ void AppendCommands(const cmCustomCommandLines& commandLines); @@ -108,6 +112,7 @@ private: bool EscapeOldStyle = true; bool UsesTerminal = false; bool CommandExpandLists = false; + bool StdPipesUTF8 = false; }; #endif diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index 2432d2bb1..60504bab7 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -14,6 +14,7 @@ #include "cmGeneratorTarget.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -111,13 +112,13 @@ void cmCustomCommandGenerator::FillEmulatorsWithArguments() if (target && target->GetType() == cmStateEnums::EXECUTABLE && !target->IsImported()) { - const char* emulator_property = + cmProp emulator_property = target->GetProperty("CROSSCOMPILING_EMULATOR"); if (!emulator_property) { continue; } - cmExpandList(emulator_property, this->EmulatorsWithArguments[c]); + cmExpandList(*emulator_property, this->EmulatorsWithArguments[c]); } } } diff --git a/Source/cmDefinePropertyCommand.cxx b/Source/cmDefinePropertyCommand.cxx index f4e4fda4d..4e2d9b08d 100644 --- a/Source/cmDefinePropertyCommand.cxx +++ b/Source/cmDefinePropertyCommand.cxx @@ -95,7 +95,7 @@ bool cmDefinePropertyCommand(std::vector<std::string> const& args, // Actually define the property. status.GetMakefile().GetState()->DefineProperty( - PropertyName, scope, BriefDocs.c_str(), FullDocs.c_str(), inherited); + PropertyName, scope, BriefDocs, FullDocs, inherited); return true; } diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx index 129a5f72f..d8aa73054 100644 --- a/Source/cmDepends.cxx +++ b/Source/cmDepends.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmDepends.h" -#include <sstream> #include <utility> #include "cmsys/FStream.hxx" @@ -10,12 +9,12 @@ #include "cmFileTime.h" #include "cmFileTimeCache.h" #include "cmGeneratedFileStream.h" -#include "cmLocalGenerator.h" +#include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -cmDepends::cmDepends(cmLocalGenerator* lg, std::string targetDir) +cmDepends::cmDepends(cmLocalUnixMakefileGenerator3* lg, std::string targetDir) : LocalGenerator(lg) , TargetDirectory(std::move(targetDir)) { @@ -81,16 +80,14 @@ void cmDepends::Clear(const std::string& file) { // Print verbose output. if (this->Verbose) { - std::ostringstream msg; - msg << "Clearing dependencies in \"" << file << "\"." << std::endl; - cmSystemTools::Stdout(msg.str()); + cmSystemTools::Stdout( + cmStrCat("Clearing dependencies in \"", file, "\".\n")); } // Write an empty dependency file. cmGeneratedFileStream depFileStream(file); depFileStream << "# Empty dependencies file\n" - << "# This may be replaced when dependencies are built." - << std::endl; + "# This may be replaced when dependencies are built.\n"; } bool cmDepends::WriteDependencies(const std::set<std::string>& /*unused*/, @@ -172,10 +169,9 @@ bool cmDepends::CheckDependencies(std::istream& internalDepends, // Print verbose output. if (this->Verbose) { - std::ostringstream msg; - msg << "Dependee \"" << dependee << "\" does not exist for depender \"" - << depender << "\"." << std::endl; - cmSystemTools::Stdout(msg.str()); + cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee, + "\" does not exist for depender \"", + depender, "\".\n")); } } else if (dependerExists) { // The dependee and depender both exist. Compare file times. @@ -185,10 +181,9 @@ bool cmDepends::CheckDependencies(std::istream& internalDepends, // Print verbose output. if (this->Verbose) { - std::ostringstream msg; - msg << "Dependee \"" << dependee << "\" is newer than depender \"" - << depender << "\"." << std::endl; - cmSystemTools::Stdout(msg.str()); + cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee, + "\" is newer than depender \"", + depender, "\".\n")); } } } else { @@ -200,11 +195,9 @@ bool cmDepends::CheckDependencies(std::istream& internalDepends, // Print verbose output. if (this->Verbose) { - std::ostringstream msg; - msg << "Dependee \"" << dependee - << "\" is newer than depends file \"" << internalDependsFileName - << "\"." << std::endl; - cmSystemTools::Stdout(msg.str()); + cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee, + "\" is newer than depends file \"", + internalDependsFileName, "\".\n")); } } } diff --git a/Source/cmDepends.h b/Source/cmDepends.h index d9387758c..8cf528f73 100644 --- a/Source/cmDepends.h +++ b/Source/cmDepends.h @@ -12,7 +12,7 @@ #include <vector> class cmFileTimeCache; -class cmLocalGenerator; +class cmLocalUnixMakefileGenerator3; /** \class cmDepends * \brief Dependency scanner superclass. @@ -29,7 +29,8 @@ public: public: /** Instances need to know the build directory name and the relative path from the build directory to the target file. */ - cmDepends(cmLocalGenerator* lg = nullptr, std::string targetDir = ""); + cmDepends(cmLocalUnixMakefileGenerator3* lg = nullptr, + std::string targetDir = ""); cmDepends(cmDepends const&) = delete; cmDepends& operator=(cmDepends const&) = delete; @@ -38,7 +39,10 @@ public: scanning dependencies. This is not a full local generator; it has been setup to do relative path conversions for the current directory. */ - void SetLocalGenerator(cmLocalGenerator* lg) { this->LocalGenerator = lg; } + void SetLocalGenerator(cmLocalUnixMakefileGenerator3* lg) + { + this->LocalGenerator = lg; + } /** Set the specific language to be scanned. */ void SetLanguage(const std::string& lang) { this->Language = lang; } @@ -92,7 +96,7 @@ protected: std::ostream& internalDepends); // The local generator. - cmLocalGenerator* LocalGenerator; + cmLocalUnixMakefileGenerator3* LocalGenerator; // Flag for verbose output. bool Verbose = false; diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index e30d9597d..e05c96444 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -7,7 +7,7 @@ #include "cmsys/FStream.hxx" #include "cmFileTime.h" -#include "cmLocalGenerator.h" +#include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -22,8 +22,9 @@ cmDependsC::cmDependsC() = default; -cmDependsC::cmDependsC(cmLocalGenerator* lg, const std::string& targetDir, - const std::string& lang, const DependencyMap* validDeps) +cmDependsC::cmDependsC(cmLocalUnixMakefileGenerator3* lg, + const std::string& targetDir, const std::string& lang, + const DependencyMap* validDeps) : cmDepends(lg, targetDir) , ValidDeps(validDeps) { @@ -211,18 +212,18 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources, // written by the original local generator for this directory // convert the dependencies to paths relative to the home output // directory. We must do the same here. - std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i); - internalDepends << obj_i << std::endl; + std::string obj_m = this->LocalGenerator->ConvertToMakefilePath(obj_i); + internalDepends << obj_i << '\n'; for (std::string const& dep : dependencies) { makeDepends << obj_m << ": " - << cmSystemTools::ConvertToOutputPath( + << this->LocalGenerator->ConvertToMakefilePath( this->LocalGenerator->MaybeConvertToRelativePath(binDir, dep)) - << std::endl; - internalDepends << " " << dep << std::endl; + << '\n'; + internalDepends << ' ' << dep << '\n'; } - makeDepends << std::endl; + makeDepends << '\n'; return true; } @@ -264,19 +265,19 @@ void cmDependsC::ReadCacheFile() // file doesn't exist, check that the regular expressions // haven't changed else if (!res) { - if (line.find(INCLUDE_REGEX_LINE_MARKER) == 0) { + if (cmHasLiteralPrefix(line, INCLUDE_REGEX_LINE_MARKER)) { if (line != this->IncludeRegexLineString) { return; } - } else if (line.find(INCLUDE_REGEX_SCAN_MARKER) == 0) { + } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_SCAN_MARKER)) { if (line != this->IncludeRegexScanString) { return; } - } else if (line.find(INCLUDE_REGEX_COMPLAIN_MARKER) == 0) { + } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_COMPLAIN_MARKER)) { if (line != this->IncludeRegexComplainString) { return; } - } else if (line.find(INCLUDE_REGEX_TRANSFORM_MARKER) == 0) { + } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_TRANSFORM_MARKER)) { if (line != this->IncludeRegexTransformString) { return; } @@ -312,17 +313,17 @@ void cmDependsC::WriteCacheFile() const for (auto const& fileIt : this->FileCache) { if (fileIt.second.Used) { - cacheOut << fileIt.first << std::endl; + cacheOut << fileIt.first << '\n'; for (UnscannedEntry const& inc : fileIt.second.UnscannedEntries) { - cacheOut << inc.FileName << std::endl; + cacheOut << inc.FileName << '\n'; if (inc.QuotedLocation.empty()) { - cacheOut << "-" << std::endl; + cacheOut << '-' << '\n'; } else { - cacheOut << inc.QuotedLocation << std::endl; + cacheOut << inc.QuotedLocation << '\n'; } } - cacheOut << std::endl; + cacheOut << '\n'; } } } @@ -383,9 +384,7 @@ void cmDependsC::SetupTransforms() // Get the transformation rules. std::vector<std::string> transformRules; cmMakefile* mf = this->LocalGenerator->GetMakefile(); - if (const char* xform = mf->GetDefinition("CMAKE_INCLUDE_TRANSFORMS")) { - cmExpandList(xform, transformRules, true); - } + mf->GetDefExpandList("CMAKE_INCLUDE_TRANSFORMS", transformRules, true); for (std::string const& tr : transformRules) { this->ParseTransform(tr); } diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h index 868c94ae9..e01faa435 100644 --- a/Source/cmDependsC.h +++ b/Source/cmDependsC.h @@ -16,7 +16,7 @@ #include "cmDepends.h" -class cmLocalGenerator; +class cmLocalUnixMakefileGenerator3; /** \class cmDependsC * \brief Dependency scanner for C and C++ object files. @@ -27,7 +27,7 @@ public: /** Checking instances need to know the build directory name and the relative path from the build directory to the target file. */ cmDependsC(); - cmDependsC(cmLocalGenerator* lg, const std::string& targetDir, + cmDependsC(cmLocalUnixMakefileGenerator3* lg, const std::string& targetDir, const std::string& lang, const DependencyMap* validDeps); /** Virtual destructor to cleanup subclasses properly. */ diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index 36922029a..8f02d9551 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -12,7 +12,7 @@ #include "cmFortranParser.h" /* Interface to parser object. */ #include "cmGeneratedFileStream.h" -#include "cmLocalGenerator.h" +#include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmOutputConverter.h" #include "cmStateDirectory.h" @@ -29,12 +29,10 @@ static void cmFortranModuleAppendUpperLower(std::string const& mod, std::string& mod_lower) { std::string::size_type ext_len = 0; - if (cmHasLiteralSuffix(mod, ".mod")) { + if (cmHasLiteralSuffix(mod, ".mod") || cmHasLiteralSuffix(mod, ".sub")) { ext_len = 4; } else if (cmHasLiteralSuffix(mod, ".smod")) { ext_len = 5; - } else if (cmHasLiteralSuffix(mod, ".sub")) { - ext_len = 4; } std::string const& name = mod.substr(0, mod.size() - ext_len); std::string const& ext = mod.substr(mod.size() - ext_len); @@ -72,7 +70,7 @@ public: cmDependsFortran::cmDependsFortran() = default; -cmDependsFortran::cmDependsFortran(cmLocalGenerator* lg) +cmDependsFortran::cmDependsFortran(cmLocalUnixMakefileGenerator3* lg) : cmDepends(lg) , Internal(new cmDependsFortranInternals) { @@ -82,10 +80,7 @@ cmDependsFortran::cmDependsFortran(cmLocalGenerator* lg) // Get the list of definitions. std::vector<std::string> definitions; cmMakefile* mf = this->LocalGenerator->GetMakefile(); - if (const char* c_defines = - mf->GetDefinition("CMAKE_TARGET_DEFINITIONS_Fortran")) { - cmExpandList(c_defines, definitions); - } + mf->GetDefExpandList("CMAKE_TARGET_DEFINITIONS_Fortran", definitions); // translate i.e. FOO=BAR to FOO and add it to the list of defined // preprocessor symbols @@ -102,10 +97,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, @@ -188,7 +180,7 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends, fiStream << "provides\n"; std::set<std::string> const& provides = this->Internal->TargetProvides; for (std::string const& i : provides) { - fiStream << " " << i << "\n"; + fiStream << ' ' << i << '\n'; } // Create a script to clean the modules. @@ -205,14 +197,14 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends, std::string mod_lower = cmStrCat(mod_dir, '/'); cmFortranModuleAppendUpperLower(i, mod_upper, mod_lower); std::string stamp = cmStrCat(stamp_dir, '/', i, ".stamp"); - fcStream << "\n"; - fcStream << " \"" + fcStream << "\n" + " \"" << this->MaybeConvertToRelativePath(currentBinDir, mod_lower) - << "\"\n"; - fcStream << " \"" + << "\"\n" + " \"" << this->MaybeConvertToRelativePath(currentBinDir, mod_upper) - << "\"\n"; - fcStream << " \"" + << "\"\n" + " \"" << this->MaybeConvertToRelativePath(currentBinDir, stamp) << "\"\n"; } @@ -248,10 +240,7 @@ void cmDependsFortran::LocateModules() // Load information about other targets. cmMakefile* mf = this->LocalGenerator->GetMakefile(); std::vector<std::string> infoFiles; - if (const char* infoFilesValue = - mf->GetDefinition("CMAKE_TARGET_LINKED_INFO_FILES")) { - cmExpandList(infoFilesValue, infoFiles); - } + mf->GetDefExpandList("CMAKE_TARGET_LINKED_INFO_FILES", infoFiles); for (std::string const& i : infoFiles) { std::string targetDir = cmSystemTools::GetFilenamePath(i); std::string fname = targetDir + "/fortran.internal"; @@ -329,16 +318,15 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj, std::string binDir = this->LocalGenerator->GetBinaryDirectory(); std::string obj_i = this->MaybeConvertToRelativePath(binDir, obj); std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i); - internalDepends << obj_i << std::endl; - internalDepends << " " << src << std::endl; + internalDepends << obj_i << "\n " << src << '\n'; for (std::string const& i : info.Includes) { makeDepends << obj_m << ": " << cmSystemTools::ConvertToOutputPath( this->MaybeConvertToRelativePath(binDir, i)) - << std::endl; - internalDepends << " " << i << std::endl; + << '\n'; + internalDepends << ' ' << i << '\n'; } - makeDepends << std::endl; + makeDepends << '\n'; // Write module requirements to the output stream. for (std::string const& i : info.Requires) { @@ -357,7 +345,7 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj, // This module is known. Depend on its timestamp file. std::string stampFile = cmSystemTools::ConvertToOutputPath( this->MaybeConvertToRelativePath(binDir, required->second)); - makeDepends << obj_m << ": " << stampFile << "\n"; + makeDepends << obj_m << ": " << stampFile << '\n'; } else { // This module is not known to CMake. Try to locate it where // the compiler will and depend on that. @@ -365,7 +353,7 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj, if (this->FindModule(i, module)) { module = cmSystemTools::ConvertToOutputPath( this->MaybeConvertToRelativePath(binDir, module)); - makeDepends << obj_m << ": " << module << "\n"; + makeDepends << obj_m << ": " << module << '\n'; } } } @@ -394,7 +382,7 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj, cmSystemTools::ConvertToOutputPath(stampFile); makeDepends << obj_m << ".provides.build" - << ": " << stampFileForMake << "\n"; + << ": " << stampFileForMake << '\n'; // Note that when cmake_copy_f90_mod finds that a module file // and the corresponding stamp file have no differences, the stamp // file is not updated. In such case the stamp file will be always @@ -402,15 +390,15 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj, // on each new build. This is expected behavior for incremental // builds and can not be changed without preforming recursive make // calls that would considerably slow down the building process. - makeDepends << stampFileForMake << ": " << obj_m << "\n"; + makeDepends << stampFileForMake << ": " << obj_m << '\n'; makeDepends << "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod " << modFile - << " " << stampFileForShell; + << ' ' << stampFileForShell; cmMakefile* mf = this->LocalGenerator->GetMakefile(); const char* cid = mf->GetDefinition("CMAKE_Fortran_COMPILER_ID"); if (cid && *cid) { - makeDepends << " " << cid; + makeDepends << ' ' << cid; } - makeDepends << "\n"; + makeDepends << '\n'; } makeDepends << obj_m << ".provides.build:\n"; // After copying the modules update the timestamp file. diff --git a/Source/cmDependsFortran.h b/Source/cmDependsFortran.h index 04851152e..3e306dd61 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> @@ -14,7 +15,7 @@ class cmDependsFortranInternals; class cmFortranSourceInfo; -class cmLocalGenerator; +class cmLocalUnixMakefileGenerator3; /** \class cmDependsFortran * \brief Dependency scanner for Fortran object files. @@ -30,7 +31,7 @@ public: path from the build directory to the target file, the source file from which to start scanning, the include file search path, and the target directory. */ - cmDependsFortran(cmLocalGenerator* lg); + cmDependsFortran(cmLocalUnixMakefileGenerator3* lg); /** Virtual destructor to cleanup subclasses properly. */ ~cmDependsFortran() override; @@ -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 516bbbfe0..fc1bbdd96 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 a673b5bbb..c545ee2b7 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/cmDynamicLoader.cxx b/Source/cmDynamicLoader.cxx index 0b72a94b2..a3731c105 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 202b20504..a8d81f7c2 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -3,6 +3,7 @@ #include "cmELF.h" #include <cstddef> +#include <cstdint> #include <map> #include <memory> #include <sstream> @@ -12,14 +13,13 @@ #include <cm/memory> #include <cmext/algorithm> -#include "cmsys/FStream.hxx" +#include <cm3p/kwiml/abi.h> -#include "cm_kwiml.h" +#include "cmsys/FStream.hxx" // Include the ELF format information system header. #if defined(__OpenBSD__) # include <elf_abi.h> -# include <stdint.h> #elif defined(__HAIKU__) # include <elf32.h> # include <elf64.h> diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 5be5bcecf..9c53bdfbc 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -10,11 +10,10 @@ #include <vector> #include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/Process.h" -#include "cm_static_string_view.hxx" - #include "cmArgumentParser.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" @@ -61,6 +60,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; }; @@ -83,7 +84,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; @@ -241,28 +244,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); diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx index 561e83066..3641cb24c 100644 --- a/Source/cmExportBuildAndroidMKGenerator.cxx +++ b/Source/cmExportBuildAndroidMKGenerator.cxx @@ -5,7 +5,8 @@ #include <sstream> #include <utility> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmGeneratorTarget.h" #include "cmLinkItem.h" #include "cmMakefile.h" @@ -46,7 +47,9 @@ void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode( os << "LOCAL_MODULE := "; os << targetName << "\n"; os << "LOCAL_SRC_FILES := "; - std::string path = cmSystemTools::ConvertToOutputPath(target->GetFullPath()); + std::string const noConfig; // FIXME: What config to use here? + std::string path = + cmSystemTools::ConvertToOutputPath(target->GetFullPath(noConfig)); os << path << "\n"; } @@ -118,13 +121,13 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( } else { bool relpath = false; if (type == cmExportBuildAndroidMKGenerator::INSTALL) { - relpath = lib.substr(0, 3) == "../"; + relpath = cmHasLiteralPrefix(lib, "../"); } // check for full path or if it already has a -l, or // in the case of an install check for relative paths // if it is full or a link library then use string directly if (cmSystemTools::FileIsFullPath(lib) || - lib.substr(0, 2) == "-l" || relpath) { + cmHasLiteralPrefix(lib, "-l") || relpath) { ldlibs += " " + lib; // if it is not a path and does not have a -l then add -l } else if (!lib.empty()) { @@ -165,7 +168,7 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( // Tell the NDK build system if prebuilt static libraries use C++. if (target->GetType() == cmStateEnums::STATIC_LIBRARY) { cmLinkImplementation const* li = target->GetLinkImplementation(config); - if (cmContains(li->Languages, "CXX")) { + if (cm::contains(li->Languages, "CXX")) { os << "LOCAL_HAS_CPP := true\n"; } } diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index d22bd4862..dd700c5ed 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -8,7 +8,8 @@ #include <sstream> #include <utility> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmExportSet.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" @@ -307,7 +308,7 @@ cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg, const auto& exportSet = exp.second; std::vector<std::string> targets; exportSet->GetTargets(targets); - if (cmContains(targets, name)) { + if (cm::contains(targets, name)) { exportFiles.push_back(exp.first); ns = exportSet->GetNamespace(); } diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index e49c17434..9f8a821e6 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -7,12 +7,11 @@ #include <utility> #include <cm/memory> +#include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/RegularExpression.hxx" -#include "cm_static_string_view.hxx" - -#include "cmAlgorithms.h" #include "cmArgumentParser.h" #include "cmExecutionStatus.h" #include "cmExportBuildAndroidMKGenerator.h" @@ -24,6 +23,7 @@ #include "cmMessageType.h" #include "cmPolicies.h" #include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" @@ -146,7 +146,7 @@ bool cmExportCommand(std::vector<std::string> const& args, } exportSet = &it->second; } else if (!arguments.Targets.empty() || - cmContains(keywordsMissingValue, "TARGETS")) { + cm::contains(keywordsMissingValue, "TARGETS")) { for (std::string const& currentTarget : arguments.Targets) { if (mf.IsAlias(currentTarget)) { std::ostringstream e; @@ -183,6 +183,28 @@ bool cmExportCommand(std::vector<std::string> const& args, return false; } + // if cmExportBuildFileGenerator is already defined for the file + // and APPEND is not specified, if CMP0103 is OLD ignore previous definition + // else raise an error + if (gg->GetExportedTargetsFile(fname) != nullptr) { + switch (mf.GetPolicyStatus(cmPolicies::CMP0103)) { + case cmPolicies::WARN: + mf.IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0103), '\n', + "export() command already specified for the file\n ", + arguments.Filename, "\nDid you miss 'APPEND' keyword?")); + CM_FALLTHROUGH; + case cmPolicies::OLD: + break; + default: + status.SetError(cmStrCat("command already specified for the file\n ", + arguments.Filename, + "\nDid you miss 'APPEND' keyword?")); + return false; + } + } + // Setup export file generation. std::unique_ptr<cmExportBuildFileGenerator> ebfg = nullptr; if (android) { diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 6441e6f29..4d0e0996a 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -21,6 +21,7 @@ #include "cmMessageType.h" #include "cmOutputConverter.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmPropertyMap.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -125,9 +126,9 @@ void cmExportFileGenerator::PopulateInterfaceProperty( const std::string& propName, cmGeneratorTarget* target, ImportPropertyMap& properties) { - const char* input = target->GetProperty(propName); + cmProp input = target->GetProperty(propName); if (input) { - properties[propName] = input; + properties[propName] = *input; } } @@ -137,16 +138,16 @@ void cmExportFileGenerator::PopulateInterfaceProperty( cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets) { - const char* input = target->GetProperty(propName); + cmProp input = target->GetProperty(propName); if (input) { - if (!*input) { + if (input->empty()) { // Set to empty properties[outputName].clear(); return; } std::string prepro = - cmGeneratorExpression::Preprocess(input, preprocessRule); + cmGeneratorExpression::Preprocess(*input, preprocessRule); if (!prepro.empty()) { this->ResolveTargetsInGeneratorExpressions(prepro, target, missingTargets); @@ -174,10 +175,10 @@ bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty( if (!target->IsLinkable()) { return false; } - const char* input = target->GetProperty("INTERFACE_LINK_LIBRARIES"); + cmProp input = target->GetProperty("INTERFACE_LINK_LIBRARIES"); if (input) { std::string prepro = - cmGeneratorExpression::Preprocess(input, preprocessRule); + cmGeneratorExpression::Preprocess(*input, preprocessRule); if (!prepro.empty()) { this->ResolveTargetsInGeneratorExpressions( prepro, target, missingTargets, ReplaceFreeTargets); @@ -276,8 +277,7 @@ static bool checkInterfaceDirs(const std::string& prepro, << "\"\nhowever it is also " "a subdirectory of the " << (inBinary ? "build" : "source") << " tree:\n \"" - << (inBinary ? topBinaryDir : topSourceDir) << "\"" - << std::endl; + << (inBinary ? topBinaryDir : topSourceDir) << "\"\n"; target->GetLocalGenerator()->IssueMessage( MessageType::AUTHOR_WARNING, s.str()); CM_FALLTHROUGH; @@ -342,19 +342,19 @@ void cmExportFileGenerator::PopulateSourcesInterface( assert(preprocessRule == cmGeneratorExpression::InstallInterface); const char* propName = "INTERFACE_SOURCES"; - const char* input = gt->GetProperty(propName); + cmProp input = gt->GetProperty(propName); if (!input) { return; } - if (!*input) { + if (input->empty()) { properties[propName].clear(); return; } std::string prepro = - cmGeneratorExpression::Preprocess(input, preprocessRule, true); + cmGeneratorExpression::Preprocess(*input, preprocessRule, true); if (!prepro.empty()) { this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets); @@ -373,7 +373,7 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( assert(preprocessRule == cmGeneratorExpression::InstallInterface); const char* propName = "INTERFACE_INCLUDE_DIRECTORIES"; - const char* input = target->GetProperty(propName); + cmProp input = target->GetProperty(propName); cmGeneratorExpression ge; @@ -400,7 +400,7 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( if (!input && exportDirs.empty()) { return; } - if ((input && !*input) && exportDirs.empty()) { + if ((input && input->empty()) && exportDirs.empty()) { // Set to empty properties[propName].clear(); return; @@ -408,7 +408,7 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( prefixItems(exportDirs); - std::string includes = (input ? input : ""); + std::string includes = (input ? *input : ""); const char* sep = input ? ";" : ""; includes += sep + exportDirs; std::string prepro = @@ -431,19 +431,19 @@ void cmExportFileGenerator::PopulateLinkDependsInterface( assert(preprocessRule == cmGeneratorExpression::InstallInterface); const char* propName = "INTERFACE_LINK_DEPENDS"; - const char* input = gt->GetProperty(propName); + cmProp input = gt->GetProperty(propName); if (!input) { return; } - if (!*input) { + if (input->empty()) { properties[propName].clear(); return; } std::string prepro = - cmGeneratorExpression::Preprocess(input, preprocessRule, true); + cmGeneratorExpression::Preprocess(*input, preprocessRule, true); if (!prepro.empty()) { this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets); @@ -462,19 +462,19 @@ void cmExportFileGenerator::PopulateLinkDirectoriesInterface( assert(preprocessRule == cmGeneratorExpression::InstallInterface); const char* propName = "INTERFACE_LINK_DIRECTORIES"; - const char* input = gt->GetProperty(propName); + cmProp input = gt->GetProperty(propName); if (!input) { return; } - if (!*input) { + if (input->empty()) { properties[propName].clear(); return; } std::string prepro = - cmGeneratorExpression::Preprocess(input, preprocessRule, true); + cmGeneratorExpression::Preprocess(*input, preprocessRule, true); if (!prepro.empty()) { this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets); @@ -497,11 +497,11 @@ void cmExportFileGenerator::PopulateInterfaceProperty( void getPropertyContents(cmGeneratorTarget const* tgt, const std::string& prop, std::set<std::string>& ifaceProperties) { - const char* p = tgt->GetProperty(prop); + cmProp p = tgt->GetProperty(prop); if (!p) { return; } - std::vector<std::string> content = cmExpandedList(p); + std::vector<std::string> content = cmExpandedList(*p); ifaceProperties.insert(content.begin(), content.end()); } @@ -762,13 +762,12 @@ void cmExportFileGenerator::SetImportLinkInterface( return; } - const char* propContent; + cmProp propContent; - if (const char* prop_suffixed = + if (cmProp prop_suffixed = target->GetProperty("LINK_INTERFACE_LIBRARIES" + suffix)) { propContent = prop_suffixed; - } else if (const char* prop = - target->GetProperty("LINK_INTERFACE_LIBRARIES")) { + } else if (cmProp prop = target->GetProperty("LINK_INTERFACE_LIBRARIES")) { propContent = prop; } else { return; @@ -790,13 +789,13 @@ void cmExportFileGenerator::SetImportLinkInterface( return; } - if (!*propContent) { + if (propContent->empty()) { properties["IMPORTED_LINK_INTERFACE_LIBRARIES" + suffix].clear(); return; } std::string prepro = - cmGeneratorExpression::Preprocess(propContent, preprocessRule); + cmGeneratorExpression::Preprocess(*propContent, preprocessRule); if (!prepro.empty()) { this->ResolveTargetsInGeneratorExpressions(prepro, target, missingTargets, ReplaceFreeTargets); @@ -856,8 +855,8 @@ void cmExportFileGenerator::SetImportDetailProperties( cmGeneratorTarget::ManagedType::Native) { std::string prop = cmStrCat("IMPORTED_COMMON_LANGUAGE_RUNTIME", suffix); std::string propval; - if (auto* p = target->GetProperty("COMMON_LANGUAGE_RUNTIME")) { - propval = p; + if (cmProp p = target->GetProperty("COMMON_LANGUAGE_RUNTIME")) { + propval = *p; } else if (target->IsCSharpOnly()) { // C# projects do not have the /clr flag, so we set the property // here to mark the target as (only) managed (i.e. no .lib file @@ -925,12 +924,14 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os) /* clang-format on */ // Isolate the file policy level. - // We use 2.6 here instead of the current version because newer - // versions of CMake should be able to export files imported by 2.6 - // until the import format changes. + // Support CMake versions as far back as 2.6 but also support using NEW + // policy settings for up to CMake 3.17 (this upper limit may be reviewed + // and increased from time to time). This reduces the opportunity for CMake + // warnings when an older export file is later used with newer CMake + // versions. /* clang-format off */ os << "cmake_policy(PUSH)\n" - << "cmake_policy(VERSION 2.6)\n"; + << "cmake_policy(VERSION 2.6...3.17)\n"; /* clang-format on */ } @@ -1116,7 +1117,7 @@ void cmExportFileGenerator::GenerateMissingTargetsCheckCode( return; } /* clang-format off */ - os << "# Make sure the targets which have been exported in some other \n" + os << "# Make sure the targets which have been exported in some other\n" "# export set exist.\n" "unset(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)\n" "foreach(_target "; @@ -1215,9 +1216,9 @@ bool cmExportFileGenerator::PopulateExportProperties( std::string& errorMessage) { auto& targetProperties = gte->Target->GetProperties(); - if (const char* exportProperties = + if (cmProp exportProperties = targetProperties.GetPropertyValue("EXPORT_PROPERTIES")) { - for (auto& prop : cmExpandedList(exportProperties)) { + for (auto& prop : cmExpandedList(*exportProperties)) { /* Black list reserved properties */ if (cmHasLiteralPrefix(prop, "IMPORTED_") || cmHasLiteralPrefix(prop, "INTERFACE_")) { @@ -1228,15 +1229,15 @@ bool cmExportFileGenerator::PopulateExportProperties( errorMessage = e.str(); return false; } - auto propertyValue = targetProperties.GetPropertyValue(prop); + cmProp propertyValue = targetProperties.GetPropertyValue(prop); if (propertyValue == nullptr) { // Asked to export a property that isn't defined on the target. Do not // consider this an error, there's just nothing to export. continue; } std::string evaluatedValue = cmGeneratorExpression::Preprocess( - propertyValue, cmGeneratorExpression::StripAllGeneratorExpressions); - if (evaluatedValue != propertyValue) { + *propertyValue, cmGeneratorExpression::StripAllGeneratorExpressions); + if (evaluatedValue != *propertyValue) { std::ostringstream e; e << "Target \"" << gte->Target->GetName() << "\" contains property \"" << prop << "\" in EXPORT_PROPERTIES but this property contains a " @@ -1244,7 +1245,7 @@ bool cmExportFileGenerator::PopulateExportProperties( errorMessage = e.str(); return false; } - properties[prop] = propertyValue; + properties[prop] = *propertyValue; } } return true; diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx index 9702e0e7c..80f776e25 100644 --- a/Source/cmExportInstallAndroidMKGenerator.cxx +++ b/Source/cmExportInstallAndroidMKGenerator.cxx @@ -66,7 +66,7 @@ void cmExportInstallAndroidMKGenerator::GenerateImportTargetCode( os << "LOCAL_MODULE := "; os << targetName << "\n"; os << "LOCAL_SRC_FILES := $(_IMPORT_PREFIX)/"; - os << target->Target->GetProperty("__dest") << "/"; + os << target->Target->GetSafeProperty("__dest") << "/"; std::string config; if (!this->Configurations.empty()) { config = this->Configurations[0]; diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx index 6011ba4b0..7f31dd218 100644 --- a/Source/cmExportLibraryDependenciesCommand.cxx +++ b/Source/cmExportLibraryDependenciesCommand.cxx @@ -14,6 +14,7 @@ #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -95,8 +96,8 @@ static void FinalAction(cmMakefile& makefile, std::string const& filename, // Handle simple output name changes. This command is // deprecated so we do not support full target name // translation (which requires per-configuration info). - if (const char* outname = libtgt->GetProperty("OUTPUT_NAME")) { - lib = outname; + if (cmProp outname = libtgt->GetProperty("OUTPUT_NAME")) { + lib = *outname; } } valueOld += lib; diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index 3df6a5c9a..c6b6184bb 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -12,6 +12,7 @@ #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmTarget.h" @@ -58,7 +59,7 @@ std::string cmExportTryCompileFileGenerator::FindTargets( const std::string& propName, cmGeneratorTarget const* tgt, std::string const& language, std::set<cmGeneratorTarget const*>& emitted) { - const char* prop = tgt->GetProperty(propName); + cmProp prop = tgt->GetProperty(propName); if (!prop) { return std::string(); } @@ -67,11 +68,11 @@ std::string cmExportTryCompileFileGenerator::FindTargets( cmGeneratorExpressionDAGChecker dagChecker(tgt, propName, nullptr, nullptr); - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop); + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*prop); cmTarget dummyHead("try_compile_dummy_exe", cmStateEnums::EXECUTABLE, cmTarget::VisibilityNormal, tgt->Target->GetMakefile(), - true); + cmTarget::PerConfig::Yes); cmGeneratorTarget gDummyHead(&dummyHead, tgt->GetLocalGenerator()); @@ -95,11 +96,11 @@ void cmExportTryCompileFileGenerator::PopulateProperties( std::vector<std::string> props = target->GetPropertyKeys(); for (std::string const& p : props) { - properties[p] = target->GetProperty(p); + properties[p] = *target->GetProperty(p); - if (p.find("IMPORTED_LINK_INTERFACE_LIBRARIES") == 0 || - p.find("IMPORTED_LINK_DEPENDENT_LIBRARIES") == 0 || - p.find("INTERFACE_LINK_LIBRARIES") == 0) { + if (cmHasLiteralPrefix(p, "IMPORTED_LINK_INTERFACE_LIBRARIES") || + cmHasLiteralPrefix(p, "IMPORTED_LINK_DEPENDENT_LIBRARIES") || + cmHasLiteralPrefix(p, "INTERFACE_LINK_LIBRARIES")) { std::string evalResult = this->FindTargets(p, target, std::string(), emitted); diff --git a/Source/cmExprParserHelper.h b/Source/cmExprParserHelper.h index eaf5dc78a..717acdcc0 100644 --- a/Source/cmExprParserHelper.h +++ b/Source/cmExprParserHelper.h @@ -8,7 +8,7 @@ #include <string> #include <vector> -#include "cm_kwiml.h" +#include <cm3p/kwiml/int.h> class cmExprParserHelper { diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index b710467c5..32b0ca93b 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -218,7 +218,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( // Convert for (std::string const& listFile : listFiles) { // don't put cmake's own files into the project (#12110): - if (listFile.find(cmSystemTools::GetCMakeRoot()) == 0) { + if (cmHasPrefix(listFile, cmSystemTools::GetCMakeRoot())) { continue; } @@ -301,11 +301,11 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( case cmStateEnums::UTILITY: // Add all utility targets, except the Nightly/Continuous/ // Experimental-"sub"targets as e.g. NightlyStart - if (((targetName.find("Nightly") == 0) && + if ((cmHasLiteralPrefix(targetName, "Nightly") && (targetName != "Nightly")) || - ((targetName.find("Continuous") == 0) && + (cmHasLiteralPrefix(targetName, "Continuous") && (targetName != "Continuous")) || - ((targetName.find("Experimental") == 0) && + (cmHasLiteralPrefix(targetName, "Experimental") && (targetName != "Experimental"))) { break; } @@ -723,7 +723,7 @@ std::string cmExtraCodeBlocksGenerator::BuildMakeCommand( if (generator == "NMake Makefiles" || generator == "NMake Makefiles JOM") { // For Windows ConvertToOutputPath already adds quotes when required. // These need to be escaped, see - // https://gitlab.kitware.com/cmake/cmake/issues/13952 + // https://gitlab.kitware.com/cmake/cmake/-/issues/13952 std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile); command += " /NOLOGO /f "; command += makefileName; @@ -731,7 +731,7 @@ std::string cmExtraCodeBlocksGenerator::BuildMakeCommand( command += target; } else if (generator == "MinGW Makefiles") { // no escaping of spaces in this case, see - // https://gitlab.kitware.com/cmake/cmake/issues/10014 + // https://gitlab.kitware.com/cmake/cmake/-/issues/10014 std::string const& makefileName = makefile; command += " -f \""; command += makefileName; diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index de40c77d5..bf7555d98 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -204,9 +204,7 @@ std::string cmExtraCodeLiteGenerator::CollectSourceFiles( case cmStateEnums::STATIC_LIBRARY: { projectType = "Static Library"; } break; - case cmStateEnums::SHARED_LIBRARY: { - projectType = "Dynamic Library"; - } break; + case cmStateEnums::SHARED_LIBRARY: case cmStateEnums::MODULE_LIBRARY: { projectType = "Dynamic Library"; } break; diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 78cabce17..7bc45360d 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -19,6 +19,7 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmProperty.h" #include "cmSourceFile.h" #include "cmSourceGroup.h" #include "cmState.h" @@ -187,10 +188,10 @@ void cmExtraEclipseCDT4Generator::CreateSettingsResourcePrefsFile() return; } - fout << "eclipse.preferences.version=1" << std::endl; + fout << "eclipse.preferences.version=1\n"; const char* encoding = mf->GetDefinition("CMAKE_ECLIPSE_RESOURCE_ENCODING"); if (encoding) { - fout << "encoding/<project>=" << encoding << std::endl; + fout << "encoding/<project>=" << encoding << '\n'; } } @@ -243,8 +244,7 @@ void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out, const bool envVarSet = cmSystemTools::GetEnv(envVar, envVarValue); std::string cacheEntryName = cmStrCat("CMAKE_ECLIPSE_ENVVAR_", envVar); - const std::string* cacheValue = - lg.GetState()->GetInitializedCacheValue(cacheEntryName); + cmProp cacheValue = lg.GetState()->GetInitializedCacheValue(cacheEntryName); // now we have both, decide which one to use std::string valueToUse; @@ -255,8 +255,8 @@ 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->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 @@ -270,7 +270,7 @@ 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()); @@ -415,9 +415,9 @@ void cmExtraEclipseCDT4Generator::CreateProjectFile() xml.Element("nature", n); } - if (const char* extraNaturesProp = + if (cmProp extraNaturesProp = mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_NATURES")) { - std::vector<std::string> extraNatures = cmExpandedList(extraNaturesProp); + std::vector<std::string> extraNatures = cmExpandedList(*extraNaturesProp); for (std::string const& n : extraNatures) { xml.Element("nature", n); } @@ -430,7 +430,7 @@ void cmExtraEclipseCDT4Generator::CreateProjectFile() if (this->IsOutOfSourceBuild) { // create a linked resource to CMAKE_SOURCE_DIR // (this is not done anymore for each project because of - // https://gitlab.kitware.com/cmake/cmake/issues/9978 and because I found + // https://gitlab.kitware.com/cmake/cmake/-/issues/9978 and because I found // it actually quite confusing in bigger projects with many directories and // projects, Alex @@ -754,11 +754,11 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const emmited.clear(); for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) { - if (const char* cdefs = + if (cmProp cdefs = lgen->GetMakefile()->GetProperty("COMPILE_DEFINITIONS")) { // Expand the list. std::vector<std::string> defs; - cmGeneratorExpression::Split(cdefs, defs); + cmGeneratorExpression::Split(*cdefs, defs); for (std::string const& d : defs) { if (cmGeneratorExpression::Find(d) != std::string::npos) { @@ -936,11 +936,11 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const case cmStateEnums::UTILITY: // Add all utility targets, except the Nightly/Continuous/ // Experimental-"sub"targets as e.g. NightlyStart - if (((targetName.find("Nightly") == 0) && + if ((cmHasLiteralPrefix(targetName, "Nightly") && (targetName != "Nightly")) || - ((targetName.find("Continuous") == 0) && + (cmHasLiteralPrefix(targetName, "Continuous") && (targetName != "Continuous")) || - ((targetName.find("Experimental") == 0) && + (cmHasLiteralPrefix(targetName, "Experimental") && (targetName != "Experimental"))) { break; } @@ -981,7 +981,6 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const } } break; case cmStateEnums::INTERFACE_LIBRARY: - break; default: break; } @@ -1033,9 +1032,9 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const xml.EndElement(); // storageModule // Append additional cproject contents without applying any XML formatting - if (const char* extraCProjectContents = + if (cmProp extraCProjectContents = mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_CPROJECT_CONTENTS")) { - fout << extraCProjectContents; + fout << *extraCProjectContents; } xml.EndElement(); // cproject diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx index 3a22846cc..01fac5a73 100644 --- a/Source/cmExtraKateGenerator.cxx +++ b/Source/cmExtraKateGenerator.cxx @@ -129,9 +129,8 @@ void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator& lg, if (targetName == "edit_cache") { const char* editCommand = localGen->GetMakefile()->GetDefinition("CMAKE_EDIT_COMMAND"); - if (editCommand == nullptr) { - insertTarget = false; - } else if (strstr(editCommand, "ccmake") != nullptr) { + if (editCommand == nullptr || + strstr(editCommand, "ccmake") != nullptr) { insertTarget = false; } } @@ -144,11 +143,11 @@ void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator& lg, case cmStateEnums::UTILITY: // Add all utility targets, except the Nightly/Continuous/ // Experimental-"sub"targets as e.g. NightlyStart - if (((targetName.find("Nightly") == 0) && + if ((cmHasLiteralPrefix(targetName, "Nightly") && (targetName != "Nightly")) || - ((targetName.find("Continuous") == 0) && + (cmHasLiteralPrefix(targetName, "Continuous") && (targetName != "Continuous")) || - ((targetName.find("Experimental") == 0) && + (cmHasLiteralPrefix(targetName, "Experimental") && (targetName != "Experimental"))) { break; } @@ -274,7 +273,7 @@ std::string cmExtraKateGenerator::GenerateProjectName( const std::string& name, const std::string& type, const std::string& path) const { - return name + (type.empty() ? "" : "-") + type + "@" + path; + return name + (type.empty() ? "" : "-") + type + '@' + path; } std::string cmExtraKateGenerator::GetPathBasename( diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 413449c78..613a94374 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -17,6 +17,7 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmProperty.h" #include "cmSourceFile.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -199,11 +200,11 @@ void cmExtraSublimeTextGenerator::AppendAllTargets( case cmStateEnums::UTILITY: // Add all utility targets, except the Nightly/Continuous/ // Experimental-"sub"targets as e.g. NightlyStart - if (((targetName.find("Nightly") == 0) && + if ((cmHasLiteralPrefix(targetName, "Nightly") && (targetName != "Nightly")) || - ((targetName.find("Continuous") == 0) && + (cmHasLiteralPrefix(targetName, "Continuous") && (targetName != "Continuous")) || - ((targetName.find("Experimental") == 0) && + (cmHasLiteralPrefix(targetName, "Experimental") && (targetName != "Experimental"))) { break; } @@ -327,7 +328,7 @@ std::string cmExtraSublimeTextGenerator::BuildMakeCommand( std::string makefileName; if (generator == "MinGW Makefiles") { // no escaping of spaces in this case, see - // https://gitlab.kitware.com/cmake/cmake/issues/10014 + // https://gitlab.kitware.com/cmake/cmake/-/issues/10014 makefileName = makefile; } else { makefileName = cmSystemTools::ConvertToOutputPath(makefile); @@ -358,14 +359,14 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject( language); const std::string COMPILE_FLAGS("COMPILE_FLAGS"); - if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) { - lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS)); + if (cmProp cflags = source->GetProperty(COMPILE_FLAGS)) { + lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS)); } const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); - if (const char* coptions = source->GetProperty(COMPILE_OPTIONS)) { + if (cmProp coptions = source->GetProperty(COMPILE_OPTIONS)) { lg->AppendCompileOptions( - flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); + flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS)); } return flags; @@ -387,17 +388,17 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines( // Add preprocessor definitions for this target and configuration. lg->GetTargetDefines(target, config, language, defines); const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); - if (const char* compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) { + if (cmProp compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) { lg->AppendDefines( - defines, genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS)); + defines, genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS)); } std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config)); - if (const char* config_compile_defs = source->GetProperty(defPropName)) { + if (cmProp config_compile_defs = source->GetProperty(defPropName)) { lg->AppendDefines( defines, - genexInterpreter.Evaluate(config_compile_defs, COMPILE_DEFINITIONS)); + genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS)); } std::string definesString; @@ -419,9 +420,9 @@ std::string cmExtraSublimeTextGenerator::ComputeIncludes( // Add include directories for this source file const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); - if (const char* cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) { + if (cmProp cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) { lg->AppendIncludeDirectories( - includes, genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES), + includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES), *source); } diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx index a56ad22f6..594969b1b 100644 --- a/Source/cmFileAPI.cxx +++ b/Source/cmFileAPI.cxx @@ -665,7 +665,7 @@ std::string cmFileAPI::NoSupportedVersion( // The "codemodel" object kind. -static unsigned int const CodeModelV2Minor = 0; +static unsigned int const CodeModelV2Minor = 1; void cmFileAPI::BuildClientRequestCodeModel( ClientRequest& r, std::vector<RequestVersion> const& versions) diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h index e183e0d97..ae076129a 100644 --- a/Source/cmFileAPI.h +++ b/Source/cmFileAPI.h @@ -11,9 +11,9 @@ #include <unordered_set> #include <vector> -#include "cm_jsoncpp_reader.h" -#include "cm_jsoncpp_value.h" -#include "cm_jsoncpp_writer.h" +#include <cm3p/json/reader.h> +#include <cm3p/json/value.h> +#include <cm3p/json/writer.h> class cmake; diff --git a/Source/cmFileAPICMakeFiles.cxx b/Source/cmFileAPICMakeFiles.cxx index 44ba96c25..1e4f3b62b 100644 --- a/Source/cmFileAPICMakeFiles.cxx +++ b/Source/cmFileAPICMakeFiles.cxx @@ -6,7 +6,7 @@ #include <string> #include <vector> -#include "cm_jsoncpp_value.h" +#include <cm3p/json/value.h> #include "cmFileAPI.h" #include "cmGlobalGenerator.h" diff --git a/Source/cmFileAPICMakeFiles.h b/Source/cmFileAPICMakeFiles.h index a851c32f4..1ae1e4f1a 100644 --- a/Source/cmFileAPICMakeFiles.h +++ b/Source/cmFileAPICMakeFiles.h @@ -5,7 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include "cm_jsoncpp_value.h" +#include <cm3p/json/value.h> class cmFileAPI; diff --git a/Source/cmFileAPICache.cxx b/Source/cmFileAPICache.cxx index ef7779567..3ba943a45 100644 --- a/Source/cmFileAPICache.cxx +++ b/Source/cmFileAPICache.cxx @@ -7,9 +7,10 @@ #include <utility> #include <vector> -#include "cm_jsoncpp_value.h" +#include <cm3p/json/value.h> #include "cmFileAPI.h" +#include "cmProperty.h" #include "cmState.h" #include "cmake.h" @@ -67,7 +68,7 @@ Json::Value Cache::DumpEntry(std::string const& name) entry["name"] = name; entry["type"] = cmState::CacheEntryTypeToString(this->State->GetCacheEntryType(name)); - entry["value"] = this->State->GetCacheEntryValue(name); + entry["value"] = this->State->GetSafeCacheEntryValue(name); Json::Value properties = this->DumpEntryProperties(name); if (!properties.empty()) { @@ -94,7 +95,8 @@ Json::Value Cache::DumpEntryProperty(std::string const& name, { Json::Value property = Json::objectValue; property["name"] = prop; - property["value"] = this->State->GetCacheEntryProperty(name, prop); + cmProp p = this->State->GetCacheEntryProperty(name, prop); + property["value"] = p ? *p : ""; return property; } } diff --git a/Source/cmFileAPICache.h b/Source/cmFileAPICache.h index 09d9e1ce9..2f30c76d5 100644 --- a/Source/cmFileAPICache.h +++ b/Source/cmFileAPICache.h @@ -5,7 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include "cm_jsoncpp_value.h" +#include <cm3p/json/value.h> class cmFileAPI; diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index 955195f4f..fe331ec8d 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -17,7 +17,7 @@ #include <cmext/algorithm> -#include "cm_jsoncpp_value.h" +#include <cm3p/json/value.h> #include "cmCryptoHash.h" #include "cmFileAPI.h" @@ -31,6 +31,7 @@ #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmSourceFile.h" #include "cmSourceGroup.h" #include "cmState.h" @@ -278,12 +279,14 @@ struct CompileData std::string Sysroot; std::vector<JBT<std::string>> Flags; std::vector<JBT<std::string>> Defines; + std::vector<JBT<std::string>> PrecompileHeaders; std::vector<IncludeEntry> Includes; friend bool operator==(CompileData const& l, CompileData const& r) { return (l.Language == r.Language && l.Sysroot == r.Sysroot && l.Flags == r.Flags && l.Defines == r.Defines && + l.PrecompileHeaders == r.PrecompileHeaders && l.Includes == r.Includes); } }; @@ -313,6 +316,10 @@ struct hash<CompileData> result = result ^ hash<std::string>()(i.Value) ^ hash<Json::ArrayIndex>()(i.Backtrace.Index); } + for (auto const& i : in.PrecompileHeaders) { + result = result ^ hash<std::string>()(i.Value) ^ + hash<Json::ArrayIndex>()(i.Backtrace.Index); + } return result; } }; @@ -369,6 +376,7 @@ class Target Json::Value DumpPaths(); Json::Value DumpCompileData(CompileData const& cd); Json::Value DumpInclude(CompileData::IncludeEntry const& inc); + Json::Value DumpPrecompileHeader(JBT<std::string> const& header); Json::Value DumpDefine(JBT<std::string> const& def); Json::Value DumpSources(); Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk, @@ -825,6 +833,11 @@ void Target::ProcessLanguage(std::string const& lang) this->ToJBT(i), this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang)); } + std::vector<BT<std::string>> precompileHeaders = + this->GT->GetPrecompileHeaders(this->Config, lang); + for (BT<std::string> const& pch : precompileHeaders) { + cd.PrecompileHeaders.emplace_back(this->ToJBT(pch)); + } } Json::ArrayIndex Target::AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si) @@ -855,8 +868,8 @@ CompileData Target::BuildCompileData(cmSourceFile* sf) fd.Language); const std::string COMPILE_FLAGS("COMPILE_FLAGS"); - if (const char* cflags = sf->GetProperty(COMPILE_FLAGS)) { - std::string flags = genexInterpreter.Evaluate(cflags, COMPILE_FLAGS); + if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) { + std::string flags = genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS); fd.Flags.emplace_back(std::move(flags), JBTIndex()); } const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); @@ -872,14 +885,27 @@ CompileData Target::BuildCompileData(cmSourceFile* sf) } // Add precompile headers compile options. - const std::string pchSource = - this->GT->GetPchSource(this->Config, fd.Language); + std::vector<std::string> architectures; + this->GT->GetAppleArchs(this->Config, architectures); + if (architectures.empty()) { + architectures.emplace_back(); + } + + std::unordered_map<std::string, std::string> pchSources; + for (const std::string& arch : architectures) { + const std::string pchSource = + this->GT->GetPchSource(this->Config, fd.Language, arch); + if (!pchSource.empty()) { + pchSources.insert(std::make_pair(pchSource, arch)); + } + } - if (!pchSource.empty() && !sf->GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (!pchSources.empty() && !sf->GetProperty("SKIP_PRECOMPILE_HEADERS")) { std::string pchOptions; - if (sf->ResolveFullPath() == pchSource) { - pchOptions = - this->GT->GetPchCreateCompileOptions(this->Config, fd.Language); + auto pchIt = pchSources.find(sf->ResolveFullPath()); + if (pchIt != pchSources.end()) { + pchOptions = this->GT->GetPchCreateCompileOptions( + this->Config, fd.Language, pchIt->second); } else { pchOptions = this->GT->GetPchUseCompileOptions(this->Config, fd.Language); @@ -936,10 +962,10 @@ CompileData Target::BuildCompileData(cmSourceFile* sf) std::set<std::string> configFileDefines; const std::string defPropName = "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(this->Config); - if (const char* config_defs = sf->GetProperty(defPropName)) { + if (cmProp config_defs = sf->GetProperty(defPropName)) { lg->AppendDefines( configFileDefines, - genexInterpreter.Evaluate(config_defs, COMPILE_DEFINITIONS)); + genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS)); } fd.Defines.reserve(fileDefines.size() + configFileDefines.size()); @@ -967,6 +993,9 @@ CompileData Target::MergeCompileData(CompileData const& fd) // All compile groups share the sysroot of the target. cd.Sysroot = td.Sysroot; + // All compile groups share the precompile headers of the target. + cd.PrecompileHeaders = td.PrecompileHeaders; + // Use target-wide flags followed by source-specific flags. cd.Flags.reserve(td.Flags.size() + fd.Flags.size()); cd.Flags.insert(cd.Flags.end(), td.Flags.begin(), td.Flags.end()); @@ -1117,6 +1146,13 @@ Json::Value Target::DumpCompileData(CompileData const& cd) } result["defines"] = std::move(defines); } + if (!cd.PrecompileHeaders.empty()) { + Json::Value precompileHeaders = Json::arrayValue; + for (JBT<std::string> const& pch : cd.PrecompileHeaders) { + precompileHeaders.append(this->DumpPrecompileHeader(pch)); + } + result["precompileHeaders"] = std::move(precompileHeaders); + } return result; } @@ -1132,6 +1168,14 @@ Json::Value Target::DumpInclude(CompileData::IncludeEntry const& inc) return include; } +Json::Value Target::DumpPrecompileHeader(JBT<std::string> const& header) +{ + Json::Value precompileHeader = Json::objectValue; + precompileHeader["header"] = header.Value; + this->AddBacktrace(precompileHeader, header.Backtrace); + return precompileHeader; +} + Json::Value Target::DumpDefine(JBT<std::string> const& def) { Json::Value define = Json::objectValue; @@ -1411,9 +1455,9 @@ Json::Value Target::DumpDependency(cmTargetDepend const& td) Json::Value Target::DumpFolder() { Json::Value folder; - if (const char* f = this->GT->GetProperty("FOLDER")) { + if (cmProp f = this->GT->GetProperty("FOLDER")) { folder = Json::objectValue; - folder["name"] = f; + folder["name"] = *f; } return folder; } diff --git a/Source/cmFileAPICodemodel.h b/Source/cmFileAPICodemodel.h index ffbd92863..a6c6bddae 100644 --- a/Source/cmFileAPICodemodel.h +++ b/Source/cmFileAPICodemodel.h @@ -5,7 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include "cm_jsoncpp_value.h" +#include <cm3p/json/value.h> class cmFileAPI; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index e36abdce8..7101e229f 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -16,13 +16,14 @@ #include <cm/memory> #include <cmext/algorithm> +#include <cmext/string_view> + +#include <cm3p/kwiml/int.h> #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" -#include "cm_kwiml.h" -#include "cm_static_string_view.hxx" #include "cm_sys_stat.h" #include "cmAlgorithms.h" @@ -33,12 +34,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" @@ -47,10 +50,11 @@ #include "cmSubcommandTable.h" #include "cmSystemTools.h" #include "cmTimestamp.h" +#include "cmWorkingDirectory.h" #include "cmake.h" #if !defined(CMAKE_BOOTSTRAP) -# include "cm_curl.h" +# include <cm3p/curl/curl.h> # include "cmCurl.h" # include "cmFileLockResult.h" @@ -672,12 +676,12 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse, } } + cmake* cm = status.GetMakefile().GetCMakeInstance(); std::vector<std::string> files; bool configureDepends = false; bool warnConfigureLate = false; bool warnFollowedSymlinks = false; - const cmake::WorkingMode workingMode = - status.GetMakefile().GetCMakeInstance()->GetWorkingMode(); + const cmake::WorkingMode workingMode = cm->GetWorkingMode(); while (i != args.end()) { if (*i == "LIST_DIRECTORIES") { ++i; // skip LIST_DIRECTORIES @@ -765,12 +769,17 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse, MessageType::AUTHOR_WARNING, "Cyclic recursion detected while globbing for '" + *i + "':\n" + globMessage.content); - } else { + } else if (globMessage.type == cmsys::Glob::error) { status.GetMakefile().IssueMessage( MessageType::FATAL_ERROR, "Error has occurred while globbing for '" + *i + "' - " + globMessage.content); shouldExit = true; + } else if (cm->GetDebugOutput() || cm->GetTrace()) { + status.GetMakefile().IssueMessage( + MessageType::LOG, + cmStrCat("Globbing for\n ", *i, "\nEncountered an error:\n ", + globMessage.content)); } } if (shouldExit) { @@ -790,7 +799,7 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse, std::sort(foundFiles.begin(), foundFiles.end()); foundFiles.erase(std::unique(foundFiles.begin(), foundFiles.end()), foundFiles.end()); - status.GetMakefile().GetCMakeInstance()->AddGlobCacheEntry( + cm->AddGlobCacheEntry( recurse, (recurse ? g.GetRecurseListDirs() : g.GetListDirs()), (recurse ? g.GetRecurseThroughSymlinks() : false), (g.GetRelative() ? g.GetRelative() : ""), expr, foundFiles, variable, @@ -1606,7 +1615,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, if (i != args.end()) { tls_verify = cmIsOn(*i); } else { - status.SetError("TLS_VERIFY missing bool value."); + status.SetError("DOWNLOAD missing bool value for TLS_VERIFY."); return false; } } else if (*i == "TLS_CAINFO") { @@ -1614,7 +1623,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, if (i != args.end()) { cainfo = i->c_str(); } else { - status.SetError("TLS_CAFILE missing file value."); + status.SetError("DOWNLOAD missing file value for TLS_CAINFO."); return false; } } else if (*i == "NETRC_FILE") { @@ -1756,11 +1765,12 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, // check to see if TLS verification is requested if (tls_verify) { res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1); - check_curl_result(res, "Unable to set TLS/SSL Verify on: "); + check_curl_result(res, "DOWNLOAD cannot set TLS/SSL Verify on: "); } else { res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); - check_curl_result(res, "Unable to set TLS/SSL Verify off: "); + check_curl_result(res, "DOWNLOAD cannot set TLS/SSL Verify off: "); } + // check to see if a CAINFO file has been specified // command arg comes first std::string const& cainfo_err = cmCurlSetCAInfo(curl, cainfo); @@ -1925,6 +1935,8 @@ bool HandleUploadCommand(std::vector<std::string> const& args, std::string logVar; std::string statusVar; bool showProgress = false; + bool tls_verify = status.GetMakefile().IsOn("CMAKE_TLS_VERIFY"); + const char* cainfo = status.GetMakefile().GetDefinition("CMAKE_TLS_CAINFO"); std::string userpwd; std::string netrc_level = status.GetMakefile().GetSafeDefinition("CMAKE_NETRC"); @@ -1966,6 +1978,22 @@ bool HandleUploadCommand(std::vector<std::string> const& args, statusVar = *i; } else if (*i == "SHOW_PROGRESS") { showProgress = true; + } else if (*i == "TLS_VERIFY") { + ++i; + if (i != args.end()) { + tls_verify = cmIsOn(*i); + } else { + status.SetError("UPLOAD missing bool value for TLS_VERIFY."); + return false; + } + } else if (*i == "TLS_CAINFO") { + ++i; + if (i != args.end()) { + cainfo = i->c_str(); + } else { + status.SetError("UPLOAD missing file value for TLS_CAINFO."); + return false; + } } else if (*i == "NETRC_FILE") { ++i; if (i != args.end()) { @@ -2051,8 +2079,18 @@ bool HandleUploadCommand(std::vector<std::string> const& args, cmFileCommandCurlDebugCallback); check_curl_result(res, "UPLOAD cannot set debug function: "); - // make sure default CAInfo is set - std::string const& cainfo_err = cmCurlSetCAInfo(curl, nullptr); + // check to see if TLS verification is requested + if (tls_verify) { + res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1); + check_curl_result(res, "UPLOAD cannot set TLS/SSL Verify on: "); + } else { + res = ::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + check_curl_result(res, "UPLOAD cannot set TLS/SSL Verify off: "); + } + + // check to see if a CAINFO file has been specified + // command arg comes first + std::string const& cainfo_err = cmCurlSetCAInfo(curl, cainfo); if (!cainfo_err.empty()) { status.SetError(cainfo_err); return false; @@ -2330,12 +2368,9 @@ bool HandleLockCommand(std::vector<std::string> const& args, path += "/cmake.lock"; } - if (!cmsys::SystemTools::FileIsFullPath(path)) { - path = status.GetMakefile().GetCurrentSourceDirectory() + "/" + path; - } - // Unify path (remove '//', '/../', ...) - path = cmSystemTools::CollapseFullPath(path); + path = cmSystemTools::CollapseFullPath( + path, status.GetMakefile().GetCurrentSourceDirectory()); // Create file and directories if needed std::string parentDir = cmSystemTools::GetParentDirectory(path); @@ -2783,6 +2818,314 @@ 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 = cmSystemTools::CollapseFullPath( + args[2], status.GetMakefile().GetCurrentBinaryDirectory()); + + 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; +} + +bool HandleArchiveCreateCommand(std::vector<std::string> const& args, + cmExecutionStatus& status) +{ + struct Arguments + { + std::string Output; + std::string Format; + std::string Compression; + std::string MTime; + bool Verbose = false; + std::vector<std::string> Paths; + }; + + static auto const parser = cmArgumentParser<Arguments>{} + .Bind("OUTPUT"_s, &Arguments::Output) + .Bind("FORMAT"_s, &Arguments::Format) + .Bind("COMPRESSION"_s, &Arguments::Compression) + .Bind("MTIME"_s, &Arguments::MTime) + .Bind("VERBOSE"_s, &Arguments::Verbose) + .Bind("PATHS"_s, &Arguments::Paths); + + std::vector<std::string> unrecognizedArguments; + std::vector<std::string> keywordsMissingValues; + auto parsedArgs = + parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, + &keywordsMissingValues); + auto argIt = unrecognizedArguments.begin(); + if (argIt != unrecognizedArguments.end()) { + status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\"")); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + const std::vector<std::string> LIST_ARGS = { "OUTPUT", "FORMAT", + "COMPRESSION", "MTIME", + "PATHS" }; + auto kwbegin = keywordsMissingValues.cbegin(); + auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); + if (kwend != kwbegin) { + status.SetError(cmStrCat("Keywords missing values:\n ", + cmJoin(cmMakeRange(kwbegin, kwend), "\n "))); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + const char* knownFormats[] = { + "7zip", "gnutar", "pax", "paxr", "raw", "zip" + }; + + if (!parsedArgs.Format.empty() && + !cm::contains(knownFormats, parsedArgs.Format)) { + status.SetError( + cmStrCat("archive format ", parsedArgs.Format, " not supported")); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + const char* zipFileFormats[] = { "7zip", "zip" }; + if (!parsedArgs.Compression.empty() && + cm::contains(zipFileFormats, parsedArgs.Format)) { + status.SetError(cmStrCat("archive format ", parsedArgs.Format, + " does not support COMPRESSION arguments")); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + static std::map<std::string, cmSystemTools::cmTarCompression> + compressionTypeMap = { { "None", cmSystemTools::TarCompressNone }, + { "BZip2", cmSystemTools::TarCompressBZip2 }, + { "GZip", cmSystemTools::TarCompressGZip }, + { "XZ", cmSystemTools::TarCompressXZ }, + { "Zstd", cmSystemTools::TarCompressZstd } }; + + cmSystemTools::cmTarCompression compress = cmSystemTools::TarCompressNone; + auto typeIt = compressionTypeMap.find(parsedArgs.Compression); + if (typeIt != compressionTypeMap.end()) { + compress = typeIt->second; + } else if (!parsedArgs.Compression.empty()) { + status.SetError(cmStrCat("compression type ", parsedArgs.Compression, + " is not supported")); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + if (parsedArgs.Paths.empty()) { + status.SetError("ARCHIVE_CREATE requires a non-empty list of PATHS"); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + if (!cmSystemTools::CreateTar(parsedArgs.Output, parsedArgs.Paths, compress, + parsedArgs.Verbose, parsedArgs.MTime, + parsedArgs.Format)) { + status.SetError(cmStrCat("failed to compress: ", parsedArgs.Output)); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + return true; +} + +bool HandleArchiveExtractCommand(std::vector<std::string> const& args, + cmExecutionStatus& status) +{ + struct Arguments + { + std::string Input; + bool Verbose = false; + bool ListOnly = false; + std::string Destination; + std::vector<std::string> Patterns; + }; + + static auto const parser = cmArgumentParser<Arguments>{} + .Bind("INPUT"_s, &Arguments::Input) + .Bind("VERBOSE"_s, &Arguments::Verbose) + .Bind("LIST_ONLY"_s, &Arguments::ListOnly) + .Bind("DESTINATION"_s, &Arguments::Destination) + .Bind("PATTERNS"_s, &Arguments::Patterns); + + std::vector<std::string> unrecognizedArguments; + std::vector<std::string> keywordsMissingValues; + auto parsedArgs = + parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, + &keywordsMissingValues); + auto argIt = unrecognizedArguments.begin(); + if (argIt != unrecognizedArguments.end()) { + status.SetError(cmStrCat("Unrecognized argument: \"", *argIt, "\"")); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + const std::vector<std::string> LIST_ARGS = { "INPUT", "DESTINATION", + "PATTERNS" }; + auto kwbegin = keywordsMissingValues.cbegin(); + auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS); + if (kwend != kwbegin) { + status.SetError(cmStrCat("Keywords missing values:\n ", + cmJoin(cmMakeRange(kwbegin, kwend), "\n "))); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + std::string inFile = parsedArgs.Input; + + if (parsedArgs.ListOnly) { + if (!cmSystemTools::ListTar(inFile, parsedArgs.Patterns, + parsedArgs.Verbose)) { + status.SetError(cmStrCat("failed to list: ", inFile)); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + } else { + std::string destDir = status.GetMakefile().GetCurrentBinaryDirectory(); + if (!parsedArgs.Destination.empty()) { + if (cmSystemTools::FileIsFullPath(parsedArgs.Destination)) { + destDir = parsedArgs.Destination; + } else { + destDir = cmStrCat(destDir, "/", parsedArgs.Destination); + } + + if (!cmSystemTools::MakeDirectory(destDir)) { + status.SetError(cmStrCat("failed to create directory: ", destDir)); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + if (!cmSystemTools::FileIsFullPath(inFile)) { + inFile = + cmStrCat(cmSystemTools::GetCurrentWorkingDirectory(), "/", inFile); + } + } + + cmWorkingDirectory workdir(destDir); + if (workdir.Failed()) { + status.SetError( + cmStrCat("failed to change working directory to: ", destDir)); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + + if (!cmSystemTools::ExtractTar(inFile, parsedArgs.Patterns, + parsedArgs.Verbose)) { + status.SetError(cmStrCat("failed to extract: ", inFile)); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + } + + return true; +} + } // namespace bool cmFileCommand(std::vector<std::string> const& args, @@ -2836,6 +3179,9 @@ bool cmFileCommand(std::vector<std::string> const& args, { "READ_SYMLINK"_s, HandleReadSymlinkCommand }, { "CREATE_LINK"_s, HandleCreateLinkCommand }, { "GET_RUNTIME_DEPENDENCIES"_s, HandleGetRuntimeDependenciesCommand }, + { "CONFIGURE"_s, HandleConfigureCommand }, + { "ARCHIVE_CREATE"_s, HandleArchiveCreateCommand }, + { "ARCHIVE_EXTRACT"_s, HandleArchiveExtractCommand }, }; return subcommand(args[0], args, status); diff --git a/Source/cmFileMonitor.h b/Source/cmFileMonitor.h index b510a2cd2..fc75b0cee 100644 --- a/Source/cmFileMonitor.h +++ b/Source/cmFileMonitor.h @@ -9,7 +9,7 @@ #include <string> #include <vector> -#include "cm_uv.h" +#include <cm3p/uv.h> class cmRootWatcher; diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx index bec99bb7e..743ac75fa 100644 --- a/Source/cmFindBase.cxx +++ b/Source/cmFindBase.cxx @@ -10,6 +10,7 @@ #include <cmext/algorithm> #include "cmMakefile.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmSearchPath.h" #include "cmState.h" @@ -22,10 +23,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) @@ -115,6 +112,10 @@ 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 { @@ -296,7 +297,7 @@ bool cmFindBase::CheckForVariableInCache() if (const char* cacheValue = this->Makefile->GetDefinition(this->VariableName)) { cmState* state = this->Makefile->GetState(); - const char* cacheEntry = state->GetCacheEntryValue(this->VariableName); + cmProp cacheEntry = state->GetCacheEntryValue(this->VariableName); bool found = !cmIsNOTFOUND(cacheValue); bool cached = cacheEntry != nullptr; if (found) { @@ -312,9 +313,9 @@ bool cmFindBase::CheckForVariableInCache() return true; } if (cached) { - const char* hs = + cmProp hs = state->GetCacheEntryProperty(this->VariableName, "HELPSTRING"); - this->VariableDocumentation = hs ? hs : "(none)"; + this->VariableDocumentation = hs ? *hs : "(none)"; } } return false; diff --git a/Source/cmFindBase.h b/Source/cmFindBase.h index fce0b1189..4cbf09ef3 100644 --- a/Source/cmFindBase.h +++ b/Source/cmFindBase.h @@ -44,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. diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index 82acfedad..3e97150e7 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -4,7 +4,6 @@ #include <algorithm> #include <array> -#include <cstring> #include <utility> #include <cmext/algorithm> @@ -280,12 +279,7 @@ void cmFindCommon::GetIgnoredPaths(std::vector<std::string>& ignore) // Construct the list of path roots with no trailing slashes. for (const char** pathName = paths; *pathName; ++pathName) { // Get the list of paths to ignore from the variable. - const char* ignorePath = this->Makefile->GetDefinition(*pathName); - if ((ignorePath == nullptr) || (strlen(ignorePath) == 0)) { - continue; - } - - cmExpandList(ignorePath, ignore); + this->Makefile->GetDefExpandList(*pathName, ignore); } for (std::string& i : ignore) { diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx index d5a4bde97..3242b6d97 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" @@ -75,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; } @@ -425,7 +433,8 @@ bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path, #endif if (name.Regex.find(testName)) { this->TestPath = cmStrCat(path, origName); - if (!cmSystemTools::FileIsDirectory(this->TestPath)) { + // Make sure the path is readable and is not a directory. + if (cmSystemTools::FileExists(this->TestPath, true)) { this->DebugLibraryFound(name.Raw, dir); // This is a matching file. Check if it is better than the diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 297c72b0f..8d5b177f2 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -24,6 +24,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmSearchPath.h" #include "cmState.h" @@ -279,9 +280,13 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) } else if (args[i] == "MODULE") { moduleArgs.insert(i); doing = DoingNone; + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) } else if (args[i] == "CONFIG") { configArgs.insert(i); doing = DoingNone; + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) } else if (args[i] == "NO_MODULE") { configArgs.insert(i); doing = DoingNone; @@ -318,6 +323,8 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) this->NoSystemRegistry = true; configArgs.insert(i); doing = DoingNone; + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) } else if (args[i] == "NO_CMAKE_BUILDS_PATH") { // Ignore legacy option. configArgs.insert(i); @@ -498,9 +505,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) case cmPolicies::NEW: { // NEW behavior is to honor the <pkg>_ROOT variables. std::string const rootVar = this->Name + "_ROOT"; - if (const char* pkgRoot = this->Makefile->GetDefinition(rootVar)) { - cmExpandList(pkgRoot, rootPaths, false); - } + this->Makefile->GetDefExpandList(rootVar, rootPaths, false); cmSystemTools::GetPath(rootPaths, rootVar.c_str()); } break; } @@ -1060,8 +1065,8 @@ 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; } @@ -1114,12 +1119,10 @@ bool cmFindPackageCommand::ReadListFile(const std::string& f, void cmFindPackageCommand::AppendToFoundProperty(bool found) { std::vector<std::string> foundContents; - const char* foundProp = + cmProp foundProp = this->Makefile->GetState()->GetGlobalProperty("PACKAGES_FOUND"); - if (foundProp && *foundProp) { - std::string tmp = foundProp; - - cmExpandList(tmp, foundContents, false); + if (foundProp && !foundProp->empty()) { + cmExpandList(*foundProp, foundContents, false); auto nameIt = std::find(foundContents.begin(), foundContents.end(), this->Name); if (nameIt != foundContents.end()) { @@ -1128,12 +1131,10 @@ void cmFindPackageCommand::AppendToFoundProperty(bool found) } std::vector<std::string> notFoundContents; - const char* notFoundProp = + cmProp notFoundProp = this->Makefile->GetState()->GetGlobalProperty("PACKAGES_NOT_FOUND"); - if (notFoundProp && *notFoundProp) { - std::string tmp = notFoundProp; - - cmExpandList(tmp, notFoundContents, false); + if (notFoundProp && !notFoundProp->empty()) { + cmExpandList(*notFoundProp, notFoundContents, false); auto nameIt = std::find(notFoundContents.begin(), notFoundContents.end(), this->Name); if (nameIt != notFoundContents.end()) { diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h index ae9ade73e..7058a54ea 100644 --- a/Source/cmFindPackageCommand.h +++ b/Source/cmFindPackageCommand.h @@ -12,7 +12,7 @@ #include <string> #include <vector> -#include "cm_kwiml.h" +#include <cm3p/kwiml/int.h> #include "cmFindCommon.h" #include "cmPolicies.h" diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx index 908f0c13c..4bab46976 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" @@ -43,14 +44,21 @@ 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; } diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx index 3e4917262..4b88bea4d 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" @@ -127,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; } diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index 054618659..3b82e0a2d 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -4,7 +4,7 @@ #include <algorithm> #include <cassert> -#include <cstddef> +#include <cstddef> // IWYU pragma: keep // 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" @@ -18,8 +18,7 @@ #include <cm/memory> #include <cm/string_view> - -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmExecutionStatus.h" #include "cmFunctionBlocker.h" @@ -114,8 +113,8 @@ bool cmForEachFunctionBlocker::ReplayItems( // At end of for each execute recorded commands // store the old value std::string oldDef; - if (mf.GetDefinition(this->Args.front())) { - oldDef = mf.GetDefinition(this->Args.front()); + if (auto d = mf.GetDefinition(this->Args.front())) { + oldDef = d; } auto restore = false; @@ -187,8 +186,8 @@ bool cmForEachFunctionBlocker::ReplayZipLists( // 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])); + if (auto d = mf.GetDefinition(iterationVars[i])) { + oldDefs.emplace(iterationVars[i], d); } } diff --git a/Source/cmFunctionBlocker.cxx b/Source/cmFunctionBlocker.cxx index 5778a7152..643cd823f 100644 --- a/Source/cmFunctionBlocker.cxx +++ b/Source/cmFunctionBlocker.cxx @@ -3,7 +3,9 @@ #include "cmFunctionBlocker.h" #include <cassert> +#include <memory> // IWYU pragma: keep #include <sstream> +#include <string> // IWYU pragma: keep #include <utility> #include "cmExecutionStatus.h" diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index a4c907232..b6f58bd05 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -7,8 +7,7 @@ #include <cm/memory> #include <cm/string_view> #include <cmext/algorithm> - -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmExecutionStatus.h" #include "cmFunctionBlocker.h" diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx index 2af04b691..9cee0e6e9 100644 --- a/Source/cmGeneratedFileStream.cxx +++ b/Source/cmGeneratedFileStream.cxx @@ -8,8 +8,9 @@ #include "cmSystemTools.h" #if !defined(CMAKE_BOOTSTRAP) +# include <cm3p/zlib.h> + # include "cm_codecvt.hxx" -# include "cm_zlib.h" #endif cmGeneratedFileStream::cmGeneratedFileStream(Encoding encoding) @@ -180,6 +181,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 81d1e4692..6e293d51a 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -32,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, @@ -52,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, @@ -103,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; } @@ -119,6 +104,7 @@ cmCompiledGeneratorExpression::cmCompiledGeneratorExpression( , Quiet(false) , HadContextSensitiveCondition(false) , HadHeadSensitiveCondition(false) + , HadLinkLanguageSensitiveCondition(false) { cmGeneratorExpressionLexer l; std::vector<cmGeneratorExpressionToken> tokens = l.Tokenize(this->Input); diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index c4be3a13b..75bba02d2 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 { @@ -137,6 +129,10 @@ public: { return this->HadHeadSensitiveCondition; } + bool GetHadLinkLanguageSensitiveCondition() const + { + return this->HadLinkLanguageSensitiveCondition; + } std::set<cmGeneratorTarget const*> GetSourceSensitiveTargets() const { return this->SourceSensitiveTargets; @@ -178,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 6d973310c..42cbe2a4c 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 4709fa024..bceff12bd 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 643ba346d..4f379cd7b 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -6,6 +6,9 @@ #include <sstream> #include <utility> +#include <cm/string_view> +#include <cmext/string_view> + #include "cmGeneratorExpressionContext.h" #include "cmGeneratorExpressionEvaluator.h" #include "cmGeneratorTarget.h" @@ -44,12 +47,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( void cmGeneratorExpressionDAGChecker::Initialize() { - const cmGeneratorExpressionDAGChecker* top = this; - const cmGeneratorExpressionDAGChecker* p = this->Parent; - while (p) { - top = p; - p = p->Parent; - } + const auto* top = this->Top(); this->CheckResult = this->CheckGraph(); #define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) top->METHOD() || @@ -140,61 +138,57 @@ cmGeneratorExpressionDAGChecker::CheckGraph() const return DAG; } -bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly() +bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly() const { - const cmGeneratorExpressionDAGChecker* top = this; - const cmGeneratorExpressionDAGChecker* parent = this->Parent; - while (parent) { - top = parent; - parent = parent->Parent; - } + return this->Top()->TransitivePropertiesOnly; +} - return top->TransitivePropertiesOnly; +bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression() const +{ + return cmHasLiteralPrefix(this->Property, "TARGET_GENEX_EVAL:") || + cmHasLiteralPrefix(this->Property, "GENEX_EVAL:"); } -bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression() +bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() const { - return this->Property.find("TARGET_GENEX_EVAL:") == 0 || - this->Property.find("GENEX_EVAL:", 0) == 0; + return this->Top()->Property == "INTERFACE_POSITION_INDEPENDENT_CODE"; } -bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() +bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const { - const cmGeneratorExpressionDAGChecker* top = this; - const cmGeneratorExpressionDAGChecker* parent = this->Parent; - while (parent) { - top = parent; - parent = parent->Parent; - } + cm::string_view property(this->Top()->Property); + + return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s || + property == "LINK_DEPENDS"_s; +} + +bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const +{ + cm::string_view property(this->Top()->Property); - return top->Property == "INTERFACE_POSITION_INDEPENDENT_CODE"; + return property == "LINK_OPTIONS"_s; } bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries( - cmGeneratorTarget const* tgt) + cmGeneratorTarget const* tgt) const { - const cmGeneratorExpressionDAGChecker* top = this; - const cmGeneratorExpressionDAGChecker* parent = this->Parent; - while (parent) { - top = parent; - parent = parent->Parent; - } + const auto* top = this->Top(); - 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 +cmGeneratorExpressionDAGChecker const* cmGeneratorExpressionDAGChecker::Top() + const { const cmGeneratorExpressionDAGChecker* top = this; const cmGeneratorExpressionDAGChecker* parent = this->Parent; @@ -202,7 +196,12 @@ cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const top = parent; parent = parent->Parent; } - return top->Target; + return top; +} + +cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const +{ + return this->Top()->Target; } enum TransitiveProperty diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index f2c49bbf2..c2c5b6b6b 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -66,9 +66,12 @@ struct cmGeneratorExpressionDAGChecker void ReportError(cmGeneratorExpressionContext* context, const std::string& expr); - bool EvaluatingGenexExpression(); - bool EvaluatingPICExpression(); - bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr); + bool EvaluatingGenexExpression() const; + bool EvaluatingPICExpression() const; + bool EvaluatingLinkExpression() const; + bool EvaluatingLinkOptionsExpression() const; + + bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr) const; #define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const; @@ -76,9 +79,10 @@ struct cmGeneratorExpressionDAGChecker #undef DECLARE_TRANSITIVE_PROPERTY_METHOD - bool GetTransitivePropertiesOnly(); + bool GetTransitivePropertiesOnly() const; void SetTransitivePropertiesOnly() { this->TransitivePropertiesOnly = true; } + cmGeneratorExpressionDAGChecker const* Top() const; cmGeneratorTarget const* TopTarget() const; private: diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 14478c22c..e4fb67e69 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -15,12 +15,13 @@ #include <cm/iterator> #include <cm/string_view> +#include <cm/vector> +#include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/RegularExpression.hxx" #include "cmsys/String.h" -#include "cm_static_string_view.hxx" - #include "cmAlgorithms.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionContext.h" @@ -34,6 +35,7 @@ #include "cmMessageType.h" #include "cmOutputConverter.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmState.h" #include "cmStateSnapshot.h" @@ -62,6 +64,9 @@ std::string cmGeneratorExpressionNode::EvaluateDependentExpression( if (cge->GetHadHeadSensitiveCondition()) { context->HadHeadSensitiveCondition = true; } + if (cge->GetHadLinkLanguageSensitiveCondition()) { + context->HadLinkLanguageSensitiveCondition = true; + } return result; } @@ -310,7 +315,7 @@ static const struct InListNode : public cmGeneratorExpressionNode break; } - return cmContains(values, parameters.front()) ? "1" : "0"; + return cm::contains(values, parameters.front()) ? "1" : "0"; } } inListNode; @@ -904,22 +909,21 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode } if (context->CurrentTarget && context->CurrentTarget->IsImported()) { - const char* loc = nullptr; - const char* imp = nullptr; + cmProp loc = nullptr; + cmProp imp = nullptr; std::string suffix; - if (context->CurrentTarget->Target->GetMappedConfig( - context->Config, &loc, &imp, suffix)) { + if (context->CurrentTarget->Target->GetMappedConfig(context->Config, loc, + imp, suffix)) { // This imported target has an appropriate location // for this (possibly mapped) config. // Check if there is a proper config mapping for the tested config. std::vector<std::string> mappedConfigs; std::string mapProp = cmStrCat( "MAP_IMPORTED_CONFIG_", cmSystemTools::UpperCase(context->Config)); - if (const char* mapValue = - context->CurrentTarget->GetProperty(mapProp)) { - cmExpandList(cmSystemTools::UpperCase(mapValue), mappedConfigs); - return cmContains(mappedConfigs, - cmSystemTools::UpperCase(parameters.front())) + if (cmProp mapValue = context->CurrentTarget->GetProperty(mapProp)) { + cmExpandList(cmSystemTools::UpperCase(*mapValue), mappedConfigs); + return cm::contains(mappedConfigs, + cmSystemTools::UpperCase(parameters.front())) ? "1" : "0"; } @@ -1039,6 +1043,214 @@ 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; + +static const struct HostLinkNode : public cmGeneratorExpressionNode +{ + HostLinkNode() {} // 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->EvaluatingLinkOptionsExpression()) { + reportError(context, content->GetOriginalExpression(), + "$<HOST_LINK:...> may only be used with binary targets " + "to specify link options."); + return std::string(); + } + + return context->HeadTarget->IsDeviceLink() ? std::string() + : cmJoin(parameters, ";"); + } +} hostLinkNode; + +static const struct DeviceLinkNode : public cmGeneratorExpressionNode +{ + DeviceLinkNode() {} // 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->EvaluatingLinkOptionsExpression()) { + reportError(context, content->GetOriginalExpression(), + "$<DEVICE_LINK:...> may only be used with binary targets " + "to specify link options."); + return std::string(); + } + + if (context->HeadTarget->IsDeviceLink()) { + std::vector<std::string> list; + cmExpandLists(parameters.begin(), parameters.end(), list); + const auto DL_BEGIN = "<DEVICE_LINK>"_s; + const auto DL_END = "</DEVICE_LINK>"_s; + cm::erase_if(list, [&](const std::string& item) { + return item == DL_BEGIN || item == DL_END; + }); + + list.insert(list.begin(), static_cast<std::string>(DL_BEGIN)); + list.push_back(static_cast<std::string>(DL_END)); + + return cmJoin(list, ";"); + } + + return std::string(); + } +} deviceLinkNode; + std::string getLinkedTargetsContent( cmGeneratorTarget const* target, std::string const& prop, cmGeneratorExpressionContext* context, @@ -1130,6 +1342,14 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } return std::string(); } + if (propertyName == "ALIAS_GLOBAL"_s) { + if (context->LG->GetMakefile()->IsAlias(targetName)) { + return context->LG->GetGlobalGenerator()->IsAlias(targetName) + ? "TRUE" + : "FALSE"; + } + return std::string(); + } target = context->LG->FindGeneratorTargetToUse(targetName); if (!target) { @@ -1156,6 +1376,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode context, content->GetOriginalExpression(), "$<TARGET_PROPERTY:prop> may only be used with binary targets. " "It may not be used with add_custom_command or add_custom_target. " + " " "Specify the target to read a property from using the " "$<TARGET_PROPERTY:tgt,prop> signature instead."); return std::string(); @@ -1270,8 +1491,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode std::string result; bool haveProp = false; - if (const char* p = target->GetProperty(propertyName)) { - result = p; + if (cmProp p = target->GetProperty(propertyName)) { + result = *p; haveProp = true; } else if (evaluatingLinkLibraries) { return std::string(); @@ -1418,11 +1639,11 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode std::vector<std::string> objects; if (gt->IsImported()) { - const char* loc = nullptr; - const char* imp = nullptr; + cmProp loc = nullptr; + cmProp imp = nullptr; std::string suffix; - if (gt->Target->GetMappedConfig(context->Config, &loc, &imp, suffix)) { - cmExpandList(loc, objects); + if (gt->Target->GetMappedConfig(context->Config, loc, imp, suffix)) { + cmExpandList(*loc, objects); } context->HadContextSensitiveCondition = true; } else { @@ -1509,13 +1730,13 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode for (auto const& lit : testedFeatures) { std::vector<std::string> const& langAvailable = availableFeatures[lit.first]; - const char* standardDefault = context->LG->GetMakefile()->GetDefinition( + cmProp standardDefault = context->LG->GetMakefile()->GetDef( "CMAKE_" + lit.first + "_STANDARD_DEFAULT"); for (std::string const& it : lit.second) { - if (!cmContains(langAvailable, it)) { + if (!cm::contains(langAvailable, it)) { return "0"; } - if (standardDefault && !*standardDefault) { + if (standardDefault && standardDefault->empty()) { // This compiler has no notion of language standard levels. // All features known for the language are always available. continue; @@ -1523,12 +1744,12 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode if (!context->LG->GetMakefile()->HaveStandardAvailable( target->Target, lit.first, it)) { if (evalLL) { - const char* l = target->GetProperty(lit.first + "_STANDARD"); + cmProp l = target->GetProperty(lit.first + "_STANDARD"); if (!l) { l = standardDefault; } assert(l); - context->MaxLanguageStandard[target][lit.first] = l; + context->MaxLanguageStandard[target][lit.first] = *l; } else { return "0"; } @@ -2314,6 +2535,10 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "LINK_ONLY", &linkOnlyNode }, { "COMPILE_LANG_AND_ID", &languageAndIdNode }, { "COMPILE_LANGUAGE", &languageNode }, + { "LINK_LANG_AND_ID", &linkLanguageAndIdNode }, + { "LINK_LANGUAGE", &linkLanguageNode }, + { "HOST_LINK", &hostLinkNode }, + { "DEVICE_LINK", &deviceLinkNode }, { "SHELL_PATH", &shellPathNode } }; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 36cf213bf..f2011ee66 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -17,6 +17,8 @@ #include <cm/memory> #include <cm/string_view> +#include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/RegularExpression.hxx" @@ -35,6 +37,7 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmOutputConverter.h" #include "cmPropertyMap.h" #include "cmRange.h" #include "cmSourceFile.h" @@ -51,11 +54,11 @@ class cmMessenger; template <> -const char* cmTargetPropertyComputer::GetSources<cmGeneratorTarget>( +cmProp cmTargetPropertyComputer::GetSources<cmGeneratorTarget>( cmGeneratorTarget const* tgt, cmMessenger* /* messenger */, cmListFileBacktrace const& /* context */) { - return tgt->GetSourcesProperty().c_str(); + return &tgt->GetSourcesProperty(); } template <> @@ -236,17 +239,23 @@ EvaluatedTargetPropertyEntry EvaluateTargetPropertyEntry( return ee; } -std::vector<EvaluatedTargetPropertyEntry> EvaluateTargetPropertyEntries( +struct EvaluatedTargetPropertyEntries +{ + std::vector<EvaluatedTargetPropertyEntry> Entries; + bool HadContextSensitiveCondition = false; +}; + +EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries( cmGeneratorTarget const* thisTarget, std::string const& config, std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>> const& in) { - std::vector<EvaluatedTargetPropertyEntry> out; - out.reserve(in.size()); + EvaluatedTargetPropertyEntries out; + out.Entries.reserve(in.size()); for (auto& entry : in) { - out.emplace_back(EvaluateTargetPropertyEntry(thisTarget, config, lang, - dagChecker, *entry)); + out.Entries.emplace_back(EvaluateTargetPropertyEntry( + thisTarget, config, lang, dagChecker, *entry)); } return out; } @@ -308,6 +317,13 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) this->SourceEntries, true); this->PolicyMap = t->GetPolicyMap(); + + // Get hard-coded linker language + if (this->Target->GetProperty("HAS_CXX")) { + this->LinkerLanguage = "CXX"; + } else { + this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE"); + } } cmGeneratorTarget::~cmGeneratorTarget() = default; @@ -346,29 +362,29 @@ const std::string& cmGeneratorTarget::GetName() const std::string cmGeneratorTarget::GetExportName() const { - const char* exportName = this->GetProperty("EXPORT_NAME"); + cmProp exportName = this->GetProperty("EXPORT_NAME"); - if (exportName && *exportName) { - if (!cmGeneratorExpression::IsValidTargetName(exportName)) { + if (exportName && !exportName->empty()) { + if (!cmGeneratorExpression::IsValidTargetName(*exportName)) { std::ostringstream e; - e << "EXPORT_NAME property \"" << exportName << "\" for \"" + e << "EXPORT_NAME property \"" << *exportName << "\" for \"" << this->GetName() << "\": is not valid."; cmSystemTools::Error(e.str()); return ""; } - return exportName; + return *exportName; } return this->GetName(); } -const char* cmGeneratorTarget::GetProperty(const std::string& prop) const +cmProp cmGeneratorTarget::GetProperty(const std::string& prop) const { if (!cmTargetPropertyComputer::PassesWhitelist( this->GetType(), prop, this->Makefile->GetMessenger(), this->GetBacktrace())) { return nullptr; } - if (const char* result = cmTargetPropertyComputer::GetProperty( + if (cmProp result = cmTargetPropertyComputer::GetProperty( this, prop, this->Makefile->GetMessenger(), this->GetBacktrace())) { return result; } @@ -378,13 +394,16 @@ const char* cmGeneratorTarget::GetProperty(const std::string& prop) const return this->Target->GetProperty(prop); } -const char* cmGeneratorTarget::GetSafeProperty(const std::string& prop) const +std::string const& cmGeneratorTarget::GetSafeProperty( + std::string const& prop) const { - const char* ret = this->GetProperty(prop); - if (!ret) { - return ""; + cmProp ret = this->GetProperty(prop); + if (ret) { + return *ret; } - return ret; + + static std::string const s_empty; + return s_empty; } const char* cmGeneratorTarget::GetOutputTargetType( @@ -473,8 +492,8 @@ std::string cmGeneratorTarget::GetOutputName( std::string outName; for (std::string const& p : props) { - if (const char* outNameProp = this->GetProperty(p)) { - outName = outNameProp; + if (cmProp outNameProp = this->GetProperty(p)) { + outName = *outNameProp; break; } } @@ -530,18 +549,46 @@ std::string cmGeneratorTarget::GetFileSuffix( std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const { - const char* postfix = nullptr; + cmProp 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; + } } - return postfix ? postfix : std::string(); + return postfix ? *postfix : std::string(); +} + +std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix( + const std::string& config) const +{ + cmProp 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(); } const char* cmGeneratorTarget::GetFilePrefixInternal( @@ -574,7 +621,7 @@ const char* cmGeneratorTarget::GetFilePrefixInternal( } // Compute prefix value. - const char* targetPrefix = + cmProp targetPrefix = (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX") : this->GetProperty("PREFIX")); @@ -582,17 +629,17 @@ const char* cmGeneratorTarget::GetFilePrefixInternal( const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact); if (!language.empty() && prefixVar && *prefixVar) { std::string langPrefix = prefixVar + std::string("_") + language; - targetPrefix = this->Makefile->GetDefinition(langPrefix); + targetPrefix = this->Makefile->GetDef(langPrefix); } // if there is no prefix on the target nor specific language // use the cmake definition. if (!targetPrefix && prefixVar) { - targetPrefix = this->Makefile->GetDefinition(prefixVar); + targetPrefix = this->Makefile->GetDef(prefixVar); } } - return targetPrefix; + return targetPrefix ? targetPrefix->c_str() : nullptr; } const char* cmGeneratorTarget::GetFileSuffixInternal( std::string const& config, cmStateEnums::ArtifactType artifact, @@ -624,7 +671,7 @@ const char* cmGeneratorTarget::GetFileSuffixInternal( } // Compute suffix value. - const char* targetSuffix = + cmProp targetSuffix = (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX") : this->GetProperty("SUFFIX")); @@ -632,17 +679,17 @@ const char* cmGeneratorTarget::GetFileSuffixInternal( const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact); if (!language.empty() && suffixVar && *suffixVar) { std::string langSuffix = suffixVar + std::string("_") + language; - targetSuffix = this->Makefile->GetDefinition(langSuffix); + targetSuffix = this->Makefile->GetDef(langSuffix); } // if there is no suffix on the target nor specific language // use the cmake definition. if (!targetSuffix && suffixVar) { - targetSuffix = this->Makefile->GetDefinition(suffixVar); + targetSuffix = this->Makefile->GetDef(suffixVar); } } - return targetSuffix; + return targetSuffix ? targetSuffix->c_str() : nullptr; } void cmGeneratorTarget::ClearSourcesCache() @@ -705,9 +752,9 @@ void handleSystemIncludesDep(cmLocalGenerator* lg, std::vector<std::string>& result, bool excludeImported, std::string const& language) { - if (const char* dirs = + if (cmProp dirs = depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) { - cmExpandList(cmGeneratorExpression::Evaluate(dirs, lg, config, headTarget, + cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget, dagChecker, depTgt, language), result); } @@ -715,9 +762,8 @@ void handleSystemIncludesDep(cmLocalGenerator* lg, return; } - if (const char* dirs = - depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) { - cmExpandList(cmGeneratorExpression::Evaluate(dirs, lg, config, headTarget, + if (cmProp dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) { + cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget, dagChecker, depTgt, language), result); } @@ -773,12 +819,12 @@ const char* cmGeneratorTarget::GetFeature(const std::string& feature, if (!config.empty()) { std::string featureConfig = cmStrCat(feature, '_', cmSystemTools::UpperCase(config)); - if (const char* value = this->GetProperty(featureConfig)) { - return value; + if (cmProp value = this->GetProperty(featureConfig)) { + return value->c_str(); } } - if (const char* value = this->GetProperty(feature)) { - return value; + if (cmProp value = this->GetProperty(feature)) { + return value->c_str(); } return this->LocalGenerator->GetFeature(feature, config); } @@ -931,51 +977,12 @@ void cmGeneratorTarget::GetExternalObjects( IMPLEMENT_VISIT(SourceKindExternalObject); } -void cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& headers, - const std::string& config) const -{ - KindedSources const& kinded = this->GetKindedSources(config); - headers = kinded.ExpectedResxHeaders; -} - -void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile const*>& data, - const std::string& config) const -{ - IMPLEMENT_VISIT(SourceKindResx); -} - -void cmGeneratorTarget::GetAppManifest(std::vector<cmSourceFile const*>& data, - const std::string& config) const -{ - IMPLEMENT_VISIT(SourceKindAppManifest); -} - void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data, const std::string& config) const { IMPLEMENT_VISIT(SourceKindManifest); } -void cmGeneratorTarget::GetCertificates(std::vector<cmSourceFile const*>& data, - const std::string& config) const -{ - IMPLEMENT_VISIT(SourceKindCertificate); -} - -void cmGeneratorTarget::GetExpectedXamlHeaders(std::set<std::string>& headers, - const std::string& config) const -{ - KindedSources const& kinded = this->GetKindedSources(config); - headers = kinded.ExpectedXamlHeaders; -} - -void cmGeneratorTarget::GetExpectedXamlSources(std::set<std::string>& srcs, - const std::string& config) const -{ - KindedSources const& kinded = this->GetKindedSources(config); - srcs = kinded.ExpectedXamlSources; -} - std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const { if (!this->UtilityItemsDone) { @@ -995,12 +1002,6 @@ std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const return this->UtilityItems; } -void cmGeneratorTarget::GetXamlSources(std::vector<cmSourceFile const*>& data, - const std::string& config) const -{ - IMPLEMENT_VISIT(SourceKindXaml); -} - const std::string& cmGeneratorTarget::GetLocation( const std::string& config) const { @@ -1052,7 +1053,8 @@ const std::string& cmGeneratorTarget::GetLocationForBuild() const } // Now handle the deprecated build-time configuration location. - location = this->GetDirectory(); + std::string const noConfig; + location = this->GetDirectory(noConfig); const char* cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR"); if (cfgid && strcmp(cfgid, ".") != 0) { location += "/"; @@ -1134,8 +1136,8 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( bool& maybeInterfaceProp = i->second; // If this target itself has a non-empty property value, we are done. - const char* p = this->GetProperty(prop); - maybeInterfaceProp = p && *p; + cmProp p = this->GetProperty(prop); + maybeInterfaceProp = p && !p->empty(); // Otherwise, recurse to interface dependencies. if (!maybeInterfaceProp) { @@ -1191,7 +1193,6 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( return result; case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: // No error. We just skip cyclic references. - return result; case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: // No error. We have already seen this transitive property. return result; @@ -1202,13 +1203,16 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( cmGeneratorTarget const* headTarget = context->HeadTarget ? context->HeadTarget : this; - if (const char* p = this->GetProperty(prop)) { + if (cmProp p = this->GetProperty(prop)) { result = cmGeneratorExpressionNode::EvaluateDependentExpression( - p, context->LG, context, headTarget, &dagChecker, this); + *p, context->LG, context, headTarget, &dagChecker, this); } if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries( context->Config, headTarget, usage_requirements_only)) { + context->HadContextSensitiveCondition = + context->HadContextSensitiveCondition || + iface->HadContextSensitiveCondition; 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 @@ -1247,15 +1251,96 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( } namespace { +std::string AddSwiftInterfaceIncludeDirectories( + const cmGeneratorTarget* root, const cmGeneratorTarget* target, + const std::string& config, cmGeneratorExpressionDAGChecker* context) +{ + cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target, + "Swift_MODULE_DIRECTORY", nullptr, + context }; + switch (dag.Check()) { + case cmGeneratorExpressionDAGChecker::SELF_REFERENCE: + dag.ReportError(nullptr, + "$<TARGET_PROPERTY:" + target->GetName() + + ",Swift_MODULE_DIRECTORY>"); + CM_FALLTHROUGH; + case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: + // No error. We just skip cyclic references. + case cmGeneratorExpressionDAGChecker::ALREADY_SEEN: + // No error. We have already seen this transitive property. + return ""; + case cmGeneratorExpressionDAGChecker::DAG: + break; + } + + std::string directories; + if (const auto* interface = + target->GetLinkInterfaceLibraries(config, root, true)) { + for (const cmLinkItem& library : interface->Libraries) { + if (const cmGeneratorTarget* dependency = library.Target) { + if (cm::contains(dependency->GetAllConfigCompileLanguages(), + "Swift")) { + std::string value = + dependency->GetSafeProperty("Swift_MODULE_DIRECTORY"); + if (value.empty()) { + value = + dependency->GetLocalGenerator()->GetCurrentBinaryDirectory(); + } + + if (!directories.empty()) { + directories += ";"; + } + directories += value; + } + } + } + } + return directories; +} + +void AddSwiftImplicitIncludeDirectories( + const cmGeneratorTarget* target, const std::string& config, + EvaluatedTargetPropertyEntries& entries) +{ + if (const auto* libraries = target->GetLinkImplementationLibraries(config)) { + cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target, + "Swift_MODULE_DIRECTORY", nullptr, + nullptr }; + + for (const cmLinkImplItem& library : libraries->Libraries) { + if (const cmGeneratorTarget* dependency = library.Target) { + if (cm::contains(dependency->GetAllConfigCompileLanguages(), + "Swift")) { + EvaluatedTargetPropertyEntry entry{ library, library.Backtrace }; + + if (cmProp val = dependency->GetProperty("Swift_MODULE_DIRECTORY")) { + entry.Values.emplace_back(*val); + } else { + entry.Values.emplace_back( + dependency->GetLocalGenerator()->GetCurrentBinaryDirectory()); + } + + cmExpandList(AddSwiftInterfaceIncludeDirectories(target, dependency, + config, &dag), + entry.Values); + + entries.Entries.emplace_back(std::move(entry)); + } + } + } + } +} + void AddInterfaceEntries(cmGeneratorTarget const* headTarget, std::string const& config, std::string const& prop, std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, - std::vector<EvaluatedTargetPropertyEntry>& entries, + EvaluatedTargetPropertyEntries& entries, bool usage_requirements_only = true) { if (cmLinkImplementationLibraries const* impl = headTarget->GetLinkImplementationLibraries(config)) { + entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; for (cmLinkImplItem const& lib : impl->Libraries) { if (lib.Target) { EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace); @@ -1269,7 +1354,7 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget, prop, &context, dagChecker, usage_requirements_only), ee.Values); ee.ContextDependent = context.HadContextSensitiveCondition; - entries.emplace_back(std::move(ee)); + entries.Entries.emplace_back(std::move(ee)); } } } @@ -1278,10 +1363,11 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget, void AddObjectEntries(cmGeneratorTarget const* headTarget, std::string const& config, cmGeneratorExpressionDAGChecker* dagChecker, - std::vector<EvaluatedTargetPropertyEntry>& entries) + EvaluatedTargetPropertyEntries& entries) { if (cmLinkImplementationLibraries const* impl = headTarget->GetLinkImplementationLibraries(config)) { + entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; for (cmLinkImplItem const& lib : impl->Libraries) { if (lib.Target && lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { @@ -1300,23 +1386,23 @@ void AddObjectEntries(cmGeneratorTarget const* headTarget, if (cge->GetHadContextSensitiveCondition()) { ee.ContextDependent = true; } - entries.emplace_back(std::move(ee)); + entries.Entries.emplace_back(std::move(ee)); } } } } bool processSources(cmGeneratorTarget const* tgt, - std::vector<EvaluatedTargetPropertyEntry>& entries, + EvaluatedTargetPropertyEntries& entries, std::vector<BT<std::string>>& srcs, std::unordered_set<std::string>& uniqueSrcs, bool debugSources) { cmMakefile* mf = tgt->Target->GetMakefile(); - bool contextDependent = false; + bool contextDependent = entries.HadContextSensitiveCondition; - for (EvaluatedTargetPropertyEntry& entry : entries) { + for (EvaluatedTargetPropertyEntry& entry : entries.Entries) { if (entry.ContextDependent) { contextDependent = true; } @@ -1401,14 +1487,11 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( } std::vector<std::string> debugProperties; - const char* debugProp = - this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); - if (debugProp) { - cmExpandList(debugProp, debugProperties); - } + this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", + debugProperties); bool debugSources = - !this->DebugSourcesDone && cmContains(debugProperties, "SOURCES"); + !this->DebugSourcesDone && cm::contains(debugProperties, "SOURCES"); if (this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) { this->DebugSourcesDone = true; @@ -1417,16 +1500,15 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr, nullptr); - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, std::string(), &dagChecker, - this->SourceEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, std::string(), &dagChecker, this->SourceEntries); std::unordered_set<std::string> uniqueSrcs; bool contextDependentDirectSources = processSources(this, entries, files, uniqueSrcs, debugSources); // Collect INTERFACE_SOURCES of all direct link-dependencies. - std::vector<EvaluatedTargetPropertyEntry> linkInterfaceSourcesEntries; + EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries; AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(), &dagChecker, linkInterfaceSourcesEntries); std::vector<std::string>::size_type numFilesBefore = files.size(); @@ -1437,7 +1519,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( bool contextDependentObjects = false; std::vector<std::string>::size_type numFilesBefore2 = files.size(); if (this->GetType() != cmStateEnums::OBJECT_LIBRARY) { - std::vector<EvaluatedTargetPropertyEntry> linkObjectsEntries; + EvaluatedTargetPropertyEntries linkObjectsEntries; AddObjectEntries(this, config, &dagChecker, linkObjectsEntries); contextDependentObjects = processSources(this, linkObjectsEntries, files, uniqueSrcs, debugSources); @@ -1573,10 +1655,14 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); if (sf->GetCustomCommand()) { kind = SourceKindCustomCommand; + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) } else if (this->Target->GetType() == cmStateEnums::UTILITY) { kind = SourceKindExtra; } else if (this->IsSourceFilePartOfUnityBatch(sf->ResolveFullPath())) { kind = SourceKindUnityBatched; + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) } else if (sf->GetPropertyAsBool("HEADER_FILE_ONLY")) { kind = SourceKindHeader; } else if (sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { @@ -1595,14 +1681,6 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, } } else if (ext == "resx") { kind = SourceKindResx; - // Build and save the name of the corresponding .h file - // This relationship will be used later when building the project files. - // Both names would have been auto generated from Visual Studio - // where the user supplied the file name and Visual Studio - // appended the suffix. - std::string resx = sf->ResolveFullPath(); - std::string hFileName = resx.substr(0, resx.find_last_of('.')) + ".h"; - files.ExpectedResxHeaders.insert(hFileName); } else if (ext == "appxmanifest") { kind = SourceKindAppManifest; } else if (ext == "manifest") { @@ -1611,16 +1689,6 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, kind = SourceKindCertificate; } else if (ext == "xaml") { kind = SourceKindXaml; - // Build and save the name of the corresponding .h and .cpp file - // This relationship will be used later when building the project files. - // Both names would have been auto generated from Visual Studio - // where the user supplied the file name and Visual Studio - // appended the suffix. - std::string xaml = sf->ResolveFullPath(); - std::string hFileName = xaml + ".h"; - std::string cppFileName = xaml + ".cpp"; - files.ExpectedXamlHeaders.insert(hFileName); - files.ExpectedXamlSources.insert(cppFileName); } else if (header_regex.find(sf->ResolveFullPath())) { kind = SourceKindHeader; } else { @@ -1678,6 +1746,18 @@ void cmGeneratorTarget::ComputeAllConfigSources() const } } +std::vector<cmGeneratorTarget::AllConfigSource> +cmGeneratorTarget::GetAllConfigSources(SourceKind kind) const +{ + std::vector<AllConfigSource> result; + for (AllConfigSource const& source : this->GetAllConfigSources()) { + if (source.Kind == kind) { + result.push_back(source); + } + } + return result; +} + std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const { std::set<std::string> languages; @@ -1703,14 +1783,14 @@ std::string cmGeneratorTarget::GetCompilePDBName( // Check for a per-configuration output directory target property. std::string configUpper = cmSystemTools::UpperCase(config); std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper); - const char* config_name = this->GetProperty(configProp); - if (config_name && *config_name) { - return prefix + config_name + ".pdb"; + cmProp config_name = this->GetProperty(configProp); + if (config_name && !config_name->empty()) { + return prefix + *config_name + ".pdb"; } - const char* name = this->GetProperty("COMPILE_PDB_NAME"); - if (name && *name) { - return prefix + name + ".pdb"; + cmProp name = this->GetProperty("COMPILE_PDB_NAME"); + if (name && !name->empty()) { + return prefix + *name + ".pdb"; } return ""; @@ -1892,10 +1972,9 @@ bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir( if (this->GetType() != cmStateEnums::SHARED_LIBRARY) { return false; } - const char* install_name = this->GetProperty("INSTALL_NAME_DIR"); + cmProp install_name = this->GetProperty("INSTALL_NAME_DIR"); bool use_install_name = this->MacOSXUseInstallNameDir(); - if (install_name && use_install_name && - std::string(install_name) == "@rpath") { + if (install_name && use_install_name && *install_name == "@rpath") { install_name_is_rpath = true; } else if (install_name && use_install_name) { return false; @@ -1908,7 +1987,7 @@ bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir( if (cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config)) { if (!info->NoSOName && !info->SOName.empty()) { - if (info->SOName.find("@rpath/") == 0) { + if (cmHasLiteralPrefix(info->SOName, "@rpath/")) { install_name_is_rpath = true; } } else { @@ -1951,7 +2030,7 @@ bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const return false; } - const char* macosx_rpath_str = this->GetProperty("MACOSX_RPATH"); + cmProp macosx_rpath_str = this->GetProperty("MACOSX_RPATH"); if (macosx_rpath_str) { return this->GetPropertyAsBool("MACOSX_RPATH"); } @@ -1968,10 +2047,10 @@ bool cmGeneratorTarget::MacOSXRpathInstallNameDirDefault() const bool cmGeneratorTarget::MacOSXUseInstallNameDir() const { - const char* build_with_install_name = + cmProp build_with_install_name = this->GetProperty("BUILD_WITH_INSTALL_NAME_DIR"); if (build_with_install_name) { - return cmIsOn(build_with_install_name); + return cmIsOn(*build_with_install_name); } cmPolicies::PolicyStatus cmp0068 = this->GetPolicyStatusCMP0068(); @@ -2025,7 +2104,7 @@ std::string cmGeneratorTarget::GetSOName(const std::string& config) const return cmSystemTools::GetFilenameName(info->Location); } // Use the soname given if any. - if (info->SOName.find("@rpath/") == 0) { + if (cmHasLiteralPrefix(info->SOName, "@rpath/")) { return info->SOName.substr(6); } return info->SOName; @@ -2053,11 +2132,8 @@ std::string cmGeneratorTarget::GetAppBundleDirectory( { std::string fpath = cmStrCat( this->GetFullName(config, cmStateEnums::RuntimeBinaryArtifact), '.'); - const char* ext = this->GetProperty("BUNDLE_EXTENSION"); - if (!ext) { - ext = "app"; - } - fpath += ext; + cmProp ext = this->GetProperty("BUNDLE_EXTENSION"); + fpath += (ext ? *ext : "app"); if (shouldAddContentLevel(level) && !this->Makefile->PlatformIsAppleEmbedded()) { fpath += "/Contents"; @@ -2079,8 +2155,10 @@ std::string cmGeneratorTarget::GetCFBundleDirectory( { std::string fpath = cmStrCat( this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.'); - const char* ext = this->GetProperty("BUNDLE_EXTENSION"); - if (!ext) { + std::string ext; + if (cmProp p = this->GetProperty("BUNDLE_EXTENSION")) { + ext = *p; + } else { if (this->IsXCTestOnApple()) { ext = "xctest"; } else { @@ -2103,11 +2181,8 @@ std::string cmGeneratorTarget::GetFrameworkDirectory( { std::string fpath = cmStrCat( this->GetOutputName(config, cmStateEnums::RuntimeBinaryArtifact), '.'); - const char* ext = this->GetProperty("BUNDLE_EXTENSION"); - if (!ext) { - ext = "framework"; - } - fpath += ext; + cmProp ext = this->GetProperty("BUNDLE_EXTENSION"); + fpath += (ext ? *ext : "framework"); if (shouldAddFullLevel(level) && !this->Makefile->PlatformIsAppleEmbedded()) { fpath += "/Versions/"; @@ -2158,11 +2233,11 @@ std::string cmGeneratorTarget::GetInstallNameDirForInstallTree( { if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) { std::string dir; - const char* install_name_dir = this->GetProperty("INSTALL_NAME_DIR"); + cmProp install_name_dir = this->GetProperty("INSTALL_NAME_DIR"); if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) { - if (install_name_dir && *install_name_dir) { - dir = install_name_dir; + if (install_name_dir && !install_name_dir->empty()) { + dir = *install_name_dir; cmGeneratorExpression::ReplaceInstallPrefix(dir, installPrefix); dir = cmGeneratorExpression::Evaluate(dir, this->LocalGenerator, config); @@ -2207,8 +2282,8 @@ const std::string* cmGeneratorTarget::GetExportMacro() const if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::MODULE_LIBRARY || this->IsExecutableWithExports()) { - if (const char* custom_export_name = this->GetProperty("DEFINE_SYMBOL")) { - this->ExportMacro = custom_export_name; + if (cmProp custom_export_name = this->GetProperty("DEFINE_SYMBOL")) { + this->ExportMacro = *custom_export_name; } else { std::string in = cmStrCat(this->GetName(), "_EXPORTS"); this->ExportMacro = cmSystemTools::MakeCidentifier(in); @@ -2224,11 +2299,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); } @@ -2270,11 +2346,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); @@ -2285,12 +2364,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( @@ -2321,7 +2407,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) { @@ -2354,40 +2440,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. @@ -2395,12 +2477,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( @@ -2450,9 +2570,9 @@ std::string cmGeneratorTarget::GetEffectiveFolderName() const return effectiveFolder; } - const char* targetFolder = this->GetProperty("FOLDER"); + cmProp targetFolder = this->GetProperty("FOLDER"); if (targetFolder) { - effectiveFolder += targetFolder; + effectiveFolder += *targetFolder; } return effectiveFolder; @@ -2644,7 +2764,7 @@ cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target) for (cmSourceFile* sf : sources) { const std::set<cmGeneratorTarget const*> tgts = this->GlobalGenerator->GetFilenameTargetDepends(sf); - if (cmContains(tgts, this->GeneratorTarget)) { + if (cm::contains(tgts, this->GeneratorTarget)) { std::ostringstream e; e << "Evaluation output file\n \"" << sf->ResolveFullPath() << "\"\ndepends on the sources of a target it is used in. This " @@ -2677,8 +2797,8 @@ void cmTargetTraceDependencies::Trace() this->CurrentEntry = &this->GeneratorTarget->SourceDepends[sf]; // Queue dependencies added explicitly by the user. - if (const char* additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) { - std::vector<std::string> objDeps = cmExpandedList(additionalDeps); + if (cmProp additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) { + std::vector<std::string> objDeps = cmExpandedList(*additionalDeps); for (std::string& objDep : objDeps) { if (cmSystemTools::FileIsFullPath(objDep)) { objDep = cmSystemTools::CollapseFullPath(objDep); @@ -2909,7 +3029,7 @@ std::string cmGeneratorTarget::GetCompilePDBDirectory( void cmGeneratorTarget::GetAppleArchs(const std::string& config, std::vector<std::string>& archVec) const { - const char* archs = nullptr; + cmProp archs = nullptr; if (!config.empty()) { std::string defVarName = cmStrCat("OSX_ARCHITECTURES_", cmSystemTools::UpperCase(config)); @@ -2919,7 +3039,139 @@ void cmGeneratorTarget::GetAppleArchs(const std::string& config, archs = this->GetProperty("OSX_ARCHITECTURES"); } if (archs) { - cmExpandList(std::string(archs), archVec); + cmExpandList(*archs, archVec); + } +} + +void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const +{ + const std::string& property = this->GetSafeProperty("CUDA_ARCHITECTURES"); + + if (property.empty()) { + switch (this->GetPolicyStatusCMP0104()) { + case cmPolicies::WARN: + if (!this->LocalGenerator->GetCMakeInstance()->GetIsInTryCompile()) { + this->Makefile->IssueMessage( + MessageType::AUTHOR_WARNING, + cmPolicies::GetPolicyWarning(cmPolicies::CMP0104) + + "\nCUDA_ARCHITECTURES is empty for target \"" + this->GetName() + + "\"."); + } + CM_FALLTHROUGH; + case cmPolicies::OLD: + break; + default: + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "CUDA_ARCHITECTURES is empty for target \"" + this->GetName() + + "\"."); + } + } + + // If CUDA_ARCHITECTURES is false we don't add any architectures. + if (cmIsOff(property)) { + return; + } + + struct CudaArchitecture + { + std::string name; + bool real{ true }; + bool virtual_{ true }; + }; + std::vector<CudaArchitecture> architectures; + + { + std::vector<std::string> options; + cmExpandList(property, options); + + for (std::string& option : options) { + CudaArchitecture architecture; + + // Architecture name is up to the first specifier. + std::size_t pos = option.find_first_of('-'); + architecture.name = option.substr(0, pos); + + if (pos != std::string::npos) { + cm::string_view specifier{ option.c_str() + pos + 1, + option.length() - pos - 1 }; + + if (specifier == "real") { + architecture.real = true; + architecture.virtual_ = false; + } else if (specifier == "virtual") { + architecture.real = false; + architecture.virtual_ = true; + } else { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "Uknown CUDA architecture specifier \"" + std::string(specifier) + + "\"."); + } + } + + architectures.emplace_back(architecture); + } + } + + std::string const& compiler = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID"); + + if (compiler == "NVIDIA") { + for (CudaArchitecture& architecture : architectures) { + flags += + " --generate-code=arch=compute_" + architecture.name + ",code=["; + + if (architecture.virtual_) { + flags += "compute_" + architecture.name; + + if (architecture.real) { + flags += ","; + } + } + + if (architecture.real) { + flags += "sm_" + architecture.name; + } + + flags += "]"; + } + } else if (compiler == "Clang") { + for (CudaArchitecture& architecture : architectures) { + flags += " --cuda-gpu-arch=sm_" + architecture.name; + + if (!architecture.real) { + Makefile->IssueMessage( + MessageType::WARNING, + "Clang doesn't support disabling CUDA real code generation."); + } + + if (!architecture.virtual_) { + flags += " --no-cuda-include-ptx=sm_" + architecture.name; + } + } + } +} + +void cmGeneratorTarget::AddCUDAToolkitFlags(std::string& flags) const +{ + std::string const& compiler = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID"); + + if (compiler == "Clang") { + // Pass CUDA toolkit explicitly to Clang. + // Clang's searching for the system CUDA toolkit isn't very good and it's + // expected the user will explicitly pass the toolkit path. + // This also avoids Clang having to search for the toolkit on every + // invocation. + std::string toolkitRoot = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_LIBRARY_ROOT"); + + if (!toolkitRoot.empty()) { + flags += " --cuda-path=" + + this->LocalGenerator->ConvertToOutputFormat(toolkitRoot, + cmOutputConverter::SHELL); + } } } @@ -2967,13 +3219,13 @@ std::string cmGeneratorTarget::GetCreateRuleVariable( } namespace { -void processIncludeDirectories( - cmGeneratorTarget const* tgt, - std::vector<EvaluatedTargetPropertyEntry>& entries, - std::vector<BT<std::string>>& includes, - std::unordered_set<std::string>& uniqueIncludes, bool debugIncludes) +void processIncludeDirectories(cmGeneratorTarget const* tgt, + EvaluatedTargetPropertyEntries& entries, + std::vector<BT<std::string>>& includes, + std::unordered_set<std::string>& uniqueIncludes, + bool debugIncludes) { - for (EvaluatedTargetPropertyEntry& entry : entries) { + for (EvaluatedTargetPropertyEntry& entry : entries.Entries) { cmLinkImplItem const& item = entry.LinkImplItem; std::string const& targetName = item.AsStr(); bool const fromImported = item.Target && item.Target->IsImported(); @@ -3081,22 +3333,22 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( nullptr, nullptr); std::vector<std::string> debugProperties; - const char* debugProp = - this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); - if (debugProp) { - cmExpandList(debugProp, debugProperties); - } + this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", + debugProperties); bool debugIncludes = !this->DebugIncludesDone && - cmContains(debugProperties, "INCLUDE_DIRECTORIES"); + cm::contains(debugProperties, "INCLUDE_DIRECTORIES"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugIncludesDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, lang, &dagChecker, - this->IncludeDirectoriesEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, lang, &dagChecker, this->IncludeDirectoriesEntries); + + if (lang == "Swift") { + AddSwiftImplicitIncludeDirectories(this, config, entries); + } AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang, &dagChecker, entries); @@ -3118,7 +3370,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( EvaluatedTargetPropertyEntry ee(lib, cmListFileBacktrace()); ee.Values.emplace_back(std::move(libDir)); - entries.emplace_back(std::move(ee)); + entries.Entries.emplace_back(std::move(ee)); } } @@ -3135,22 +3387,38 @@ enum class OptionsParse }; namespace { +const auto DL_BEGIN = "<DEVICE_LINK>"_s; +const auto DL_END = "</DEVICE_LINK>"_s; + void processOptions(cmGeneratorTarget const* tgt, - std::vector<EvaluatedTargetPropertyEntry> const& entries, + EvaluatedTargetPropertyEntries const& entries, std::vector<BT<std::string>>& options, std::unordered_set<std::string>& uniqueOptions, - bool debugOptions, const char* logName, OptionsParse parse) + bool debugOptions, const char* logName, OptionsParse parse, + bool processDeviceOptions = false) { - for (EvaluatedTargetPropertyEntry const& entry : entries) { + bool splitOption = !processDeviceOptions; + for (EvaluatedTargetPropertyEntry const& entry : entries.Entries) { std::string usedOptions; for (std::string const& opt : entry.Values) { + if (processDeviceOptions && (opt == DL_BEGIN || opt == DL_END)) { + options.emplace_back(opt, entry.Backtrace); + splitOption = opt == DL_BEGIN; + continue; + } + if (uniqueOptions.insert(opt).second) { if (parse == OptionsParse::Shell && cmHasLiteralPrefix(opt, "SHELL:")) { - std::vector<std::string> tmp; - cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp); - for (std::string& o : tmp) { - options.emplace_back(std::move(o), entry.Backtrace); + if (splitOption) { + std::vector<std::string> tmp; + cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp); + for (std::string& o : tmp) { + options.emplace_back(std::move(o), entry.Backtrace); + } + } else { + options.emplace_back(std::string(opt.c_str() + 6), + entry.Backtrace); } } else { options.emplace_back(opt, entry.Backtrace); @@ -3169,6 +3437,63 @@ void processOptions(cmGeneratorTarget const* tgt, } } } + +std::vector<BT<std::string>> wrapOptions( + std::vector<std::string>& options, const cmListFileBacktrace& bt, + const std::vector<std::string>& wrapperFlag, const std::string& wrapperSep, + bool concatFlagAndArgs) +{ + std::vector<BT<std::string>> result; + + if (options.empty()) { + return result; + } + + if (wrapperFlag.empty() || cmHasLiteralPrefix(options.front(), "LINKER:")) { + // nothing specified or LINKER wrapper, insert elements as is + result.reserve(options.size()); + for (std::string& o : options) { + result.emplace_back(std::move(o), bt); + } + } else { + if (!wrapperSep.empty()) { + if (concatFlagAndArgs) { + // insert flag elements except last one + for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) { + result.emplace_back(*i, bt); + } + // concatenate last flag element and all list values + // in one option + result.emplace_back(wrapperFlag.back() + cmJoin(options, wrapperSep), + bt); + } else { + for (std::string const& i : wrapperFlag) { + result.emplace_back(i, bt); + } + // concatenate all list values in one option + result.emplace_back(cmJoin(options, wrapperSep), bt); + } + } else { + // prefix each element of list with wrapper + if (concatFlagAndArgs) { + std::transform(options.begin(), options.end(), options.begin(), + [&wrapperFlag](std::string const& o) -> std::string { + return wrapperFlag.back() + o; + }); + } + for (std::string& o : options) { + for (auto i = wrapperFlag.begin(), + e = concatFlagAndArgs ? wrapperFlag.end() - 1 + : wrapperFlag.end(); + i != e; ++i) { + result.emplace_back(*i, bt); + } + result.emplace_back(std::move(o), bt); + } + } + } + return result; +} } void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result, @@ -3192,22 +3517,18 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions( nullptr); std::vector<std::string> debugProperties; - const char* debugProp = - this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); - if (debugProp) { - cmExpandList(debugProp, debugProperties); - } + this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", + debugProperties); bool debugOptions = !this->DebugCompileOptionsDone && - cmContains(debugProperties, "COMPILE_OPTIONS"); + cm::contains(debugProperties, "COMPILE_OPTIONS"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugCompileOptionsDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, language, &dagChecker, - this->CompileOptionsEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, language, &dagChecker, this->CompileOptionsEntries); AddInterfaceEntries(this, config, "INTERFACE_COMPILE_OPTIONS", language, &dagChecker, entries); @@ -3238,22 +3559,18 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures( nullptr); std::vector<std::string> debugProperties; - const char* debugProp = - this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); - if (debugProp) { - cmExpandList(debugProp, debugProperties); - } + this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", + debugProperties); bool debugFeatures = !this->DebugCompileFeaturesDone && - cmContains(debugProperties, "COMPILE_FEATURES"); + cm::contains(debugProperties, "COMPILE_FEATURES"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugCompileFeaturesDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, std::string(), &dagChecker, - this->CompileFeaturesEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, std::string(), &dagChecker, this->CompileFeaturesEntries); AddInterfaceEntries(this, config, "INTERFACE_COMPILE_FEATURES", std::string(), &dagChecker, entries); @@ -3286,22 +3603,18 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( nullptr, nullptr); std::vector<std::string> debugProperties; - const char* debugProp = - this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); - if (debugProp) { - cmExpandList(debugProp, debugProperties); - } + this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", + debugProperties); bool debugDefines = !this->DebugCompileDefinitionsDone && - cmContains(debugProperties, "COMPILE_DEFINITIONS"); + cm::contains(debugProperties, "COMPILE_DEFINITIONS"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugCompileDefinitionsDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, language, &dagChecker, - this->CompileDefinitionsEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, language, &dagChecker, this->CompileDefinitionsEntries); AddInterfaceEntries(this, config, "INTERFACE_COMPILE_DEFINITIONS", language, &dagChecker, entries); @@ -3309,7 +3622,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( if (!config.empty()) { std::string configPropName = "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); - const char* configProp = this->GetProperty(configPropName); + cmProp configProp = this->GetProperty(configPropName); if (configProp) { switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0043)) { case cmPolicies::WARN: { @@ -3320,8 +3633,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( } case cmPolicies::OLD: { std::unique_ptr<TargetPropertyEntry> entry = - CreateTargetPropertyEntry(configProp); - entries.emplace_back(EvaluateTargetPropertyEntry( + CreateTargetPropertyEntry(*configProp); + entries.Entries.emplace_back(EvaluateTargetPropertyEntry( this, config, language, &dagChecker, *entry)); } break; case cmPolicies::NEW: @@ -3347,11 +3660,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( nullptr, nullptr); std::vector<std::string> debugProperties; - const char* debugProp = - this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); - if (debugProp) { - cmExpandList(debugProp, debugProperties); - } + this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", + debugProperties); bool debugDefines = !this->DebugPrecompileHeadersDone && std::find(debugProperties.begin(), debugProperties.end(), @@ -3361,9 +3671,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( this->DebugPrecompileHeadersDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, language, &dagChecker, - this->PrecompileHeadersEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, language, &dagChecker, this->PrecompileHeadersEntries); AddInterfaceEntries(this, config, "INTERFACE_PRECOMPILE_HEADERS", language, &dagChecker, entries); @@ -3376,7 +3685,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( } std::string cmGeneratorTarget::GetPchHeader(const std::string& config, - const std::string& language) const + const std::string& language, + const std::string& arch) const { if (language != "C" && language != "CXX" && language != "OBJC" && language != "OBJCXX") { @@ -3387,11 +3697,11 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, return std::string(); } const cmGeneratorTarget* generatorTarget = this; - const char* pchReuseFrom = + cmProp pchReuseFrom = generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); const auto inserted = - this->PchHeaders.insert(std::make_pair(language + config, "")); + this->PchHeaders.insert(std::make_pair(language + config + arch, "")); if (inserted.second) { const std::vector<BT<std::string>> headers = this->GetPrecompileHeaders(config, language); @@ -3402,7 +3712,7 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, if (pchReuseFrom) { generatorTarget = - this->GetGlobalGenerator()->FindGeneratorTarget(pchReuseFrom); + this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom); } filename = cmStrCat( @@ -3423,7 +3733,8 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, } filename = - cmStrCat(filename, "/cmake_pch", languageToExtension.at(language)); + cmStrCat(filename, "/cmake_pch", arch.empty() ? "" : cmStrCat("_", arch), + languageToExtension.at(language)); const std::string filename_tmp = cmStrCat(filename, ".tmp"); if (!pchReuseFrom) { @@ -3482,27 +3793,28 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config, } std::string cmGeneratorTarget::GetPchSource(const std::string& config, - const std::string& language) const + const std::string& language, + const std::string& arch) const { if (language != "C" && language != "CXX" && language != "OBJC" && language != "OBJCXX") { return std::string(); } const auto inserted = - this->PchSources.insert(std::make_pair(language + config, "")); + this->PchSources.insert(std::make_pair(language + config + arch, "")); if (inserted.second) { - const std::string pchHeader = this->GetPchHeader(config, language); + const std::string pchHeader = this->GetPchHeader(config, language, arch); if (pchHeader.empty()) { return std::string(); } std::string& filename = inserted.first->second; const cmGeneratorTarget* generatorTarget = this; - const char* pchReuseFrom = + cmProp pchReuseFrom = generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); if (pchReuseFrom) { generatorTarget = - this->GetGlobalGenerator()->FindGeneratorTarget(pchReuseFrom); + this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom); } filename = @@ -3518,13 +3830,15 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config, { "OBJCXX", ".objcxx.hxx.mm" } }; - filename += languageToExtension.at(language); + filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch), + languageToExtension.at(language)); } else { const std::map<std::string, std::string> languageToExtension = { { "C", ".c" }, { "CXX", ".cxx" }, { "OBJC", ".m" }, { "OBJCXX", ".mm" } }; - filename += languageToExtension.at(language); + filename = cmStrCat(filename, arch.empty() ? "" : cmStrCat("_", arch), + languageToExtension.at(language)); } const std::string filename_tmp = cmStrCat(filename, ".tmp"); @@ -3541,16 +3855,17 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config, } std::string cmGeneratorTarget::GetPchFileObject(const std::string& config, - const std::string& language) + const std::string& language, + const std::string& arch) { if (language != "C" && language != "CXX" && language != "OBJC" && language != "OBJCXX") { return std::string(); } const auto inserted = - this->PchObjectFiles.insert(std::make_pair(language + config, "")); + this->PchObjectFiles.insert(std::make_pair(language + config + arch, "")); if (inserted.second) { - const std::string pchSource = this->GetPchSource(config, language); + const std::string pchSource = this->GetPchSource(config, language, arch); if (pchSource.empty()) { return std::string(); } @@ -3560,15 +3875,20 @@ std::string cmGeneratorTarget::GetPchFileObject(const std::string& config, pchSource, false, cmSourceFileLocationKind::Known); filename = cmStrCat(this->ObjectDirectory, this->GetObjectName(pchSf)); + if (this->GetGlobalGenerator()->IsMultiConfig()) { + cmSystemTools::ReplaceString( + filename, this->GetGlobalGenerator()->GetCMakeCFGIntDir(), config); + } } return inserted.first->second; } std::string cmGeneratorTarget::GetPchFile(const std::string& config, - const std::string& language) + const std::string& language, + const std::string& arch) { const auto inserted = - this->PchFiles.insert(std::make_pair(language + config, "")); + this->PchFiles.insert(std::make_pair(language + config + arch, "")); if (inserted.second) { std::string& pchFile = inserted.first->second; @@ -3588,20 +3908,20 @@ std::string cmGeneratorTarget::GetPchFile(const std::string& config, }; cmGeneratorTarget* generatorTarget = this; - const char* pchReuseFrom = + cmProp pchReuseFrom = generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); if (pchReuseFrom) { generatorTarget = - this->GetGlobalGenerator()->FindGeneratorTarget(pchReuseFrom); + this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom); } const std::string pchFileObject = - generatorTarget->GetPchFileObject(config, language); + generatorTarget->GetPchFileObject(config, language, arch); if (!pchExtension.empty()) { pchFile = replaceExtension(pchFileObject, pchExtension); } } else { - pchFile = this->GetPchHeader(config, language); + pchFile = this->GetPchHeader(config, language, arch); pchFile += pchExtension; } } @@ -3609,19 +3929,27 @@ std::string cmGeneratorTarget::GetPchFile(const std::string& config, } std::string cmGeneratorTarget::GetPchCreateCompileOptions( - const std::string& config, const std::string& language) + const std::string& config, const std::string& language, + const std::string& arch) { const auto inserted = this->PchCreateCompileOptions.insert( - std::make_pair(language + config, "")); + std::make_pair(language + config + arch, "")); if (inserted.second) { std::string& createOptionList = inserted.first->second; + if (this->GetPropertyAsBool("PCH_WARN_INVALID")) { + createOptionList = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH")); + } + const std::string createOptVar = cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_CREATE_PCH"); - createOptionList = this->Makefile->GetSafeDefinition(createOptVar); - const std::string pchHeader = this->GetPchHeader(config, language); - const std::string pchFile = this->GetPchFile(config, language); + createOptionList = cmStrCat( + createOptionList, ";", this->Makefile->GetSafeDefinition(createOptVar)); + + const std::string pchHeader = this->GetPchHeader(config, language, arch); + const std::string pchFile = this->GetPchFile(config, language, arch); cmSystemTools::ReplaceString(createOptionList, "<PCH_HEADER>", pchHeader); cmSystemTools::ReplaceString(createOptionList, "<PCH_FILE>", pchFile); @@ -3630,19 +3958,33 @@ std::string cmGeneratorTarget::GetPchCreateCompileOptions( } std::string cmGeneratorTarget::GetPchUseCompileOptions( - const std::string& config, const std::string& language) + const std::string& config, const std::string& language, + const std::string& arch) { - const auto inserted = - this->PchUseCompileOptions.insert(std::make_pair(language + config, "")); + const auto inserted = this->PchUseCompileOptions.insert( + std::make_pair(language + config + arch, "")); if (inserted.second) { std::string& useOptionList = inserted.first->second; + if (this->GetPropertyAsBool("PCH_WARN_INVALID")) { + useOptionList = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH")); + } + const std::string useOptVar = - cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_USE_PCH"); - useOptionList = this->Makefile->GetSafeDefinition(useOptVar); + cmStrCat(language, "_COMPILE_OPTIONS_USE_PCH"); + + std::string const& useOptionListProperty = + this->GetSafeProperty(useOptVar); - const std::string pchHeader = this->GetPchHeader(config, language); - const std::string pchFile = this->GetPchFile(config, language); + useOptionList = cmStrCat( + useOptionList, ";", + useOptionListProperty.empty() + ? this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_", useOptVar)) + : useOptionListProperty); + + const std::string pchHeader = this->GetPchHeader(config, language, arch); + const std::string pchFile = this->GetPchFile(config, language, arch); cmSystemTools::ReplaceString(useOptionList, "<PCH_HEADER>", pchHeader); cmSystemTools::ReplaceString(useOptionList, "<PCH_FILE>", pchFile); @@ -3671,6 +4013,12 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result, const std::string& config, const std::string& language) const { + if (this->IsDeviceLink() && + this->GetPolicyStatusCMP0105() != cmPolicies::NEW) { + // link options are not propagated to the device link step + return; + } + std::vector<BT<std::string>> tmp = this->GetLinkOptions(config, language); result.reserve(tmp.size()); for (BT<std::string>& v : tmp) { @@ -3688,37 +4036,83 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( nullptr); std::vector<std::string> debugProperties; - const char* debugProp = - this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); - if (debugProp) { - cmExpandList(debugProp, debugProperties); - } + this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", + debugProperties); - bool debugOptions = - !this->DebugLinkOptionsDone && cmContains(debugProperties, "LINK_OPTIONS"); + bool debugOptions = !this->DebugLinkOptionsDone && + cm::contains(debugProperties, "LINK_OPTIONS"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugLinkOptionsDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, language, &dagChecker, - this->LinkOptionsEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, language, &dagChecker, this->LinkOptionsEntries); AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language, &dagChecker, entries, this->GetPolicyStatusCMP0099() != cmPolicies::NEW); processOptions(this, entries, result, uniqueOptions, debugOptions, - "link options", OptionsParse::Shell); + "link options", OptionsParse::Shell, this->IsDeviceLink()); + + if (this->IsDeviceLink()) { + // wrap host link options + const std::string wrapper(this->Makefile->GetSafeDefinition( + "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG")); + std::vector<std::string> wrapperFlag = cmExpandedList(wrapper); + const std::string wrapperSep(this->Makefile->GetSafeDefinition( + "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG_SEP")); + bool concatFlagAndArgs = true; + if (!wrapperFlag.empty() && wrapperFlag.back() == " ") { + concatFlagAndArgs = false; + wrapperFlag.pop_back(); + } + + auto it = result.begin(); + while (it != result.end()) { + if (it->Value == DL_BEGIN) { + // device link options, no treatment + it = result.erase(it); + it = std::find_if(it, result.end(), [](const BT<std::string>& item) { + return item.Value == DL_END; + }); + if (it != result.end()) { + it = result.erase(it); + } + } else { + // host link options must be wrapped + std::vector<std::string> options; + cmSystemTools::ParseUnixCommandLine(it->Value.c_str(), options); + auto hostOptions = wrapOptions(options, it->Backtrace, wrapperFlag, + wrapperSep, concatFlagAndArgs); + it = result.erase(it); + // some compilers (like gcc 4.8 or Intel 19.0 or XLC 16) do not respect + // C++11 standard: 'std::vector::insert()' do not returns an iterator, + // so need to recompute the iterator after insertion. + if (it == result.end()) { + cm::append(result, hostOptions); + it = result.end(); + } else { + auto index = it - result.begin(); + result.insert(it, hostOptions.begin(), hostOptions.end()); + it = result.begin() + index + hostOptions.size(); + } + } + } + } // Last step: replace "LINKER:" prefixed elements by // actual linker wrapper const std::string wrapper(this->Makefile->GetSafeDefinition( - "CMAKE_" + language + "_LINKER_WRAPPER_FLAG")); + "CMAKE_" + language + + (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG" + : "_LINKER_WRAPPER_FLAG"))); std::vector<std::string> wrapperFlag = cmExpandedList(wrapper); const std::string wrapperSep(this->Makefile->GetSafeDefinition( - "CMAKE_" + language + "_LINKER_WRAPPER_FLAG_SEP")); + "CMAKE_" + language + + (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG_SEP" + : "_LINKER_WRAPPER_FLAG_SEP"))); bool concatFlagAndArgs = true; if (!wrapperFlag.empty() && wrapperFlag.back() == " ") { concatFlagAndArgs = false; @@ -3764,51 +4158,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( return result; } - std::vector<BT<std::string>> options; - if (wrapperFlag.empty()) { - // nothing specified, insert elements as is - options.reserve(linkerOptions.size()); - for (std::string& o : linkerOptions) { - options.emplace_back(std::move(o), bt); - } - } else { - if (!wrapperSep.empty()) { - if (concatFlagAndArgs) { - // insert flag elements except last one - for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) { - options.emplace_back(*i, bt); - } - // concatenate last flag element and all LINKER list values - // in one option - options.emplace_back( - wrapperFlag.back() + cmJoin(linkerOptions, wrapperSep), bt); - } else { - for (std::string const& i : wrapperFlag) { - options.emplace_back(i, bt); - } - // concatenate all LINKER list values in one option - options.emplace_back(cmJoin(linkerOptions, wrapperSep), bt); - } - } else { - // prefix each element of LINKER list with wrapper - if (concatFlagAndArgs) { - std::transform(linkerOptions.begin(), linkerOptions.end(), - linkerOptions.begin(), - [&wrapperFlag](std::string const& o) -> std::string { - return wrapperFlag.back() + o; - }); - } - for (std::string& o : linkerOptions) { - for (auto i = wrapperFlag.begin(), - e = concatFlagAndArgs ? wrapperFlag.end() - 1 - : wrapperFlag.end(); - i != e; ++i) { - options.emplace_back(*i, bt); - } - options.emplace_back(std::move(o), bt); - } - } - } + std::vector<BT<std::string>> options = wrapOptions( + linkerOptions, bt, wrapperFlag, wrapperSep, concatFlagAndArgs); result.insert(entry, options.begin(), options.end()); } return result; @@ -3835,14 +4186,14 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions( cmGeneratorExpressionDAGChecker dagChecker(this, "STATIC_LIBRARY_OPTIONS", nullptr, nullptr); - std::vector<EvaluatedTargetPropertyEntry> entries; - if (const char* linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) { - std::vector<std::string> options = cmExpandedList(linkOptions); + EvaluatedTargetPropertyEntries entries; + if (cmProp 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)); + entries.Entries.emplace_back(EvaluateTargetPropertyEntry( + this, config, language, &dagChecker, *entry)); } } processOptions(this, entries, result, uniqueOptions, false, @@ -3853,12 +4204,12 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions( namespace { void processLinkDirectories(cmGeneratorTarget const* tgt, - std::vector<EvaluatedTargetPropertyEntry>& entries, + EvaluatedTargetPropertyEntries& entries, std::vector<BT<std::string>>& directories, std::unordered_set<std::string>& uniqueDirectories, bool debugDirectories) { - for (EvaluatedTargetPropertyEntry& entry : entries) { + for (EvaluatedTargetPropertyEntry& entry : entries.Entries) { cmLinkImplItem const& item = entry.LinkImplItem; std::string const& targetName = item.AsStr(); @@ -3944,22 +4295,18 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( nullptr); std::vector<std::string> debugProperties; - const char* debugProp = - this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); - if (debugProp) { - cmExpandList(debugProp, debugProperties); - } + this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", + debugProperties); bool debugDirectories = !this->DebugLinkDirectoriesDone && - cmContains(debugProperties, "LINK_DIRECTORIES"); + cm::contains(debugProperties, "LINK_DIRECTORIES"); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugLinkDirectoriesDone = true; } - std::vector<EvaluatedTargetPropertyEntry> entries = - EvaluateTargetPropertyEntries(this, config, language, &dagChecker, - this->LinkDirectoriesEntries); + EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries( + this, config, language, &dagChecker, this->LinkDirectoriesEntries); AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language, &dagChecker, entries, @@ -3990,14 +4337,14 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr, nullptr); - std::vector<EvaluatedTargetPropertyEntry> entries; - if (const char* linkDepends = this->GetProperty("LINK_DEPENDS")) { - std::vector<std::string> depends = cmExpandedList(linkDepends); + EvaluatedTargetPropertyEntries entries; + if (cmProp 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)); + entries.Entries.emplace_back(EvaluateTargetPropertyEntry( + this, config, language, &dagChecker, *entry)); } } AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language, @@ -4152,8 +4499,8 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames( } // Check for library version properties. - const char* version = this->GetProperty("VERSION"); - const char* soversion = this->GetProperty("SOVERSION"); + cmProp version = this->GetProperty("VERSION"); + cmProp soversion = this->GetProperty("SOVERSION"); if (!this->HasSOName(config) || this->Makefile->IsOn("CMAKE_PLATFORM_NO_VERSIONED_SONAME") || this->IsFrameworkOnApple()) { @@ -4188,17 +4535,18 @@ 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, targetNames.Base, suffix, targetNames.Output, - soversion); + (soversion ? soversion->c_str() : nullptr)); // The library's real name on disk. this->ComputeVersionedName(targetNames.Real, prefix, targetNames.Base, - suffix, targetNames.Output, version); + suffix, targetNames.Output, + (version ? version->c_str() : nullptr)); } // The import library name. @@ -4231,10 +4579,13 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetExecutableNames( // This versioning is supported only for executables and then only // when the platform supports symbolic links. #if defined(_WIN32) && !defined(__CYGWIN__) - const char* version = 0; + const char* version = nullptr; #else // Check for executable version properties. - const char* version = this->GetProperty("VERSION"); + const char* version = nullptr; + if (cmProp p = this->GetProperty("VERSION")) { + version = p->c_str(); + } if (this->GetType() != cmStateEnums::EXECUTABLE || this->Makefile->IsOn("XCODE")) { version = nullptr; @@ -4364,15 +4715,23 @@ 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")) { + if (cmProp soversion = this->GetProperty("SOVERSION")) { if (this->GetType() == cmStateEnums::SHARED_LIBRARY && !isImportedLibraryArtifact && this->Makefile->IsOn("CMAKE_SHARED_LIBRARY_NAME_WITH_VERSION")) { outBase += "-"; - outBase += soversion; + outBase += *soversion; } } @@ -4403,8 +4762,8 @@ std::string cmGeneratorTarget::GetPDBOutputName( props.emplace_back("PDB_NAME"); for (std::string const& p : props) { - if (const char* outName = this->GetProperty(p)) { - base = outName; + if (cmProp outName = this->GetProperty(p)) { + base = *outName; break; } } @@ -4430,8 +4789,8 @@ std::string cmGeneratorTarget::GetPDBName(const std::string& config) const props.emplace_back("PDB_NAME"); for (std::string const& p : props) { - if (const char* outName = this->GetProperty(p)) { - base = outName; + if (cmProp outName = this->GetProperty(p)) { + base = *outName; break; } } @@ -4503,16 +4862,16 @@ cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const } else { // Handle the MACOSX_PACKAGE_LOCATION property on source files that // were not listed in one of the other lists. - if (const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) { - flags.MacFolder = location; + if (cmProp location = sf->GetProperty("MACOSX_PACKAGE_LOCATION")) { + flags.MacFolder = location->c_str(); const bool stripResources = this->GlobalGenerator->ShouldStripResourcePath(this->Makefile); - if (strcmp(location, "Resources") == 0) { + if (*location == "Resources") { flags.Type = cmGeneratorTarget::SourceFileTypeResource; if (stripResources) { flags.MacFolder = ""; } - } else if (cmHasLiteralPrefix(location, "Resources/")) { + } else if (cmHasLiteralPrefix(*location, "Resources/")) { flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource; if (stripResources) { flags.MacFolder += strlen("Resources/"); @@ -4533,8 +4892,8 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const this->SourceFileFlagsConstructed = true; // Process public headers to mark the source files. - if (const char* files = this->GetProperty("PUBLIC_HEADER")) { - std::vector<std::string> relFiles = cmExpandedList(files); + if (cmProp files = this->GetProperty("PUBLIC_HEADER")) { + std::vector<std::string> relFiles = cmExpandedList(*files); for (std::string const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { SourceFileFlags& flags = this->SourceFlagsMap[sf]; @@ -4546,8 +4905,8 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const // Process private headers after public headers so that they take // precedence if a file is listed in both. - if (const char* files = this->GetProperty("PRIVATE_HEADER")) { - std::vector<std::string> relFiles = cmExpandedList(files); + if (cmProp files = this->GetProperty("PRIVATE_HEADER")) { + std::vector<std::string> relFiles = cmExpandedList(*files); for (std::string const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { SourceFileFlags& flags = this->SourceFlagsMap[sf]; @@ -4558,8 +4917,8 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const } // Mark sources listed as resources. - if (const char* files = this->GetProperty("RESOURCE")) { - std::vector<std::string> relFiles = cmExpandedList(files); + if (cmProp files = this->GetProperty("RESOURCE")) { + std::vector<std::string> relFiles = cmExpandedList(*files); for (std::string const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { SourceFileFlags& flags = this->SourceFlagsMap[sf]; @@ -4586,9 +4945,9 @@ cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const this->GetLinkImplementationClosure(config); for (cmGeneratorTarget const* li : deps) { #define CM_READ_COMPATIBLE_INTERFACE(X, x) \ - if (const char* prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \ + if (cmProp prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \ std::vector<std::string> props; \ - cmExpandList(prop, props); \ + cmExpandList(*prop, props); \ compat.Props##x.insert(props.begin(), props.end()); \ } CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool) @@ -4696,12 +5055,12 @@ void checkPropertyConsistency(cmGeneratorTarget const* depender, const std::string& config, CompatibleType t, PropertyType* /*unused*/) { - const char* prop = dependee->GetProperty(propName); + cmProp prop = dependee->GetProperty(propName); if (!prop) { return; } - std::vector<std::string> props = cmExpandedList(prop); + std::vector<std::string> props = cmExpandedList(*prop); std::string pdir = cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/"); @@ -4855,7 +5214,8 @@ void cmGeneratorTarget::CheckPropertyCompatibility( std::ostringstream e; e << "Property \"" << prop << "\" appears in both the " << propsString << " property in the dependencies of target \"" << this->GetName() - << "\". This is not allowed. A property may only require compatibility " + << "\". This is not allowed. A property may only require " + "compatibility " "in a boolean interpretation, a numeric minimum, a numeric maximum " "or a " "string interpretation, but not a mixture."; @@ -4930,8 +5290,9 @@ bool getTypedProperty<bool>(cmGeneratorTarget const* tgt, return tgt->GetPropertyAsBool(prop); } - const char* value = tgt->GetProperty(prop); - return cmIsOn(genexInterpreter->Evaluate(value, prop)); + cmProp value = tgt->GetProperty(prop); + return cmIsOn( + genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop)); } template <> @@ -4939,13 +5300,14 @@ const char* getTypedProperty<const char*>( cmGeneratorTarget const* tgt, const std::string& prop, cmGeneratorExpressionInterpreter* genexInterpreter) { - const char* value = tgt->GetProperty(prop); + cmProp value = tgt->GetProperty(prop); if (genexInterpreter == nullptr) { - return value; + return value ? value->c_str() : nullptr; } - return genexInterpreter->Evaluate(value, prop).c_str(); + return genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop) + .c_str(); } template <> @@ -4953,13 +5315,13 @@ std::string getTypedProperty<std::string>( cmGeneratorTarget const* tgt, const std::string& prop, cmGeneratorExpressionInterpreter* genexInterpreter) { - const char* value = tgt->GetProperty(prop); + cmProp value = tgt->GetProperty(prop); if (genexInterpreter == nullptr) { - return valueAsString(value); + return valueAsString(value ? value->c_str() : nullptr); } - return genexInterpreter->Evaluate(value, prop); + return genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop); } template <typename PropertyType> @@ -5104,7 +5466,7 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, PropertyType propContent = getTypedProperty<PropertyType>(tgt, p); std::vector<std::string> headPropKeys = tgt->GetPropertyKeys(); - const bool explicitlySet = cmContains(headPropKeys, p); + const bool explicitlySet = cm::contains(headPropKeys, p); const bool impliedByUse = tgt->IsNullImpliedByLinkLibraries(p); assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet)); @@ -5144,7 +5506,7 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, std::vector<std::string> propKeys = theTarget->GetPropertyKeys(); - const bool ifaceIsSet = cmContains(propKeys, interfaceProperty); + const bool ifaceIsSet = cm::contains(propKeys, interfaceProperty); PropertyType ifacePropContent = getTypedProperty<PropertyType>( theTarget, interfaceProperty, genexInterpreter.get()); @@ -5237,6 +5599,13 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, return propContent; } +bool cmGeneratorTarget::SetDeviceLink(bool deviceLink) +{ + bool previous = this->DeviceLink; + this->DeviceLink = deviceLink; + return previous; +} + bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty( const std::string& p, const std::string& config) const { @@ -5323,13 +5692,13 @@ void cmGeneratorTarget::GetTargetVersion(const std::string& property, assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY); - if (const char* version = this->GetProperty(property)) { + if (cmProp version = this->GetProperty(property)) { // Try to parse the version number and store the results that were // successfully parsed. int parsed_major; int parsed_minor; int parsed_patch; - switch (sscanf(version, "%d.%d.%d", &parsed_major, &parsed_minor, + switch (sscanf(version->c_str(), "%d.%d.%d", &parsed_major, &parsed_minor, &parsed_patch)) { case 3: patch = parsed_patch; @@ -5346,6 +5715,25 @@ void cmGeneratorTarget::GetTargetVersion(const std::string& property, } } +std::string cmGeneratorTarget::GetRuntimeLinkLibrary( + std::string const& lang, std::string const& config) const +{ + // This is activated by the presence of a default selection whether or + // not it is overridden by a property. + cmProp runtimeLibraryDefault = this->Makefile->GetDef( + cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT")); + if (!runtimeLibraryDefault || runtimeLibraryDefault->empty()) { + return std::string(); + } + cmProp runtimeLibraryValue = + this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY")); + if (!runtimeLibraryValue) { + runtimeLibraryValue = runtimeLibraryDefault; + } + return cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate( + *runtimeLibraryValue, this->LocalGenerator, config, this)); +} + std::string cmGeneratorTarget::GetFortranModuleDirectory( std::string const& working_dir) const { @@ -5363,8 +5751,8 @@ std::string cmGeneratorTarget::CreateFortranModuleDirectory( { std::string mod_dir; std::string target_mod_dir; - if (const char* prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) { - target_mod_dir = prop; + if (cmProp prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) { + target_mod_dir = *prop; } else { std::string const& default_mod_dir = this->LocalGenerator->GetCurrentBinaryDirectory(); @@ -5395,11 +5783,11 @@ std::string cmGeneratorTarget::GetFrameworkVersion() const { assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY); - if (const char* fversion = this->GetProperty("FRAMEWORK_VERSION")) { - return fversion; + if (cmProp fversion = this->GetProperty("FRAMEWORK_VERSION")) { + return *fversion; } - if (const char* tversion = this->GetProperty("VERSION")) { - return tversion; + if (cmProp tversion = this->GetProperty("VERSION")) { + return *tversion; } return "A"; } @@ -5429,14 +5817,11 @@ void cmGeneratorTarget::ReportPropertyOrigin( const std::string& compatibilityType) const { std::vector<std::string> debugProperties; - const char* debugProp = this->Target->GetMakefile()->GetDefinition( - "CMAKE_DEBUG_TARGET_PROPERTIES"); - if (debugProp) { - cmExpandList(debugProp, debugProperties); - } + this->Target->GetMakefile()->GetDefExpandList( + "CMAKE_DEBUG_TARGET_PROPERTIES", debugProperties); - bool debugOrigin = - !this->DebugCompatiblePropertiesDone[p] && cmContains(debugProperties, p); + bool debugOrigin = !this->DebugCompatiblePropertiesDone[p] && + cm::contains(debugProperties, p); if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { this->DebugCompatiblePropertiesDone[p] = true; @@ -5492,31 +5877,44 @@ void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names, 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& hadContextSensitiveCondition, + 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 - // link dependencies that are otherwise excluded from usage requirements. + // The $<LINK_ONLY> expression may be in a link interface to specify + // private link dependencies that are otherwise excluded from usage + // requirements. if (usage_requirements_only) { dagChecker.SetTransitivePropertiesOnly(); } 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(); + hadContextSensitiveCondition = cge->GetHadContextSensitiveCondition(); + 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 @@ -5529,6 +5927,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) { @@ -5543,7 +5945,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); } } @@ -5554,6 +5956,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 || @@ -5565,7 +5974,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) { @@ -5575,9 +5985,9 @@ void cmGeneratorTarget::ComputeLinkInterface( } } else { // TODO: Recognize shared library file names. Perhaps this - // should be moved to cmComputeLinkInformation, but that creates - // a chicken-and-egg problem since this list is needed for its - // construction. + // should be moved to cmComputeLinkInformation, but that + // creates a chicken-and-egg problem since this list is needed + // for its construction. } } } @@ -5595,7 +6005,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; } } @@ -5612,11 +6022,11 @@ void cmGeneratorTarget::ComputeLinkInterface( // How many repetitions are needed if this library has cyclic // dependencies? std::string propName = cmStrCat("LINK_INTERFACE_MULTIPLICITY", suffix); - if (const char* config_reps = this->GetProperty(propName)) { - sscanf(config_reps, "%u", &iface.Multiplicity); - } else if (const char* reps = + if (cmProp config_reps = this->GetProperty(propName)) { + sscanf(config_reps->c_str(), "%u", &iface.Multiplicity); + } else if (cmProp reps = this->GetProperty("LINK_INTERFACE_MULTIPLICITY")) { - sscanf(reps, "%u", &iface.Multiplicity); + sscanf(reps->c_str(), "%u", &iface.Multiplicity); } } } @@ -5638,7 +6048,6 @@ const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries( } // Lookup any existing link interface for this configuration. - std::string CONFIG = cmSystemTools::UpperCase(config); cmHeadToLinkInterfaceMap& hm = (usage_requirements_only ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config) @@ -5767,21 +6176,21 @@ bool cmGeneratorTarget::ComputeOutputDir(const std::string& config, } // Select an output directory. - if (const char* config_outdir = this->GetProperty(configProp)) { + if (cmProp config_outdir = this->GetProperty(configProp)) { // Use the user-specified per-configuration output directory. - out = cmGeneratorExpression::Evaluate(config_outdir, this->LocalGenerator, + out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator, config); // Skip per-configuration subdirectory. conf.clear(); - } else if (const char* outdir = this->GetProperty(propertyName)) { + } else if (cmProp outdir = this->GetProperty(propertyName)) { // Use the user-specified output directory. out = - cmGeneratorExpression::Evaluate(outdir, this->LocalGenerator, config); + cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config); // Skip per-configuration subdirectory if the value contained a // generator expression. - if (out != outdir) { + if (out != *outdir) { conf.clear(); } } else if (this->GetType() == cmStateEnums::EXECUTABLE) { @@ -5843,21 +6252,21 @@ bool cmGeneratorTarget::ComputePDBOutputDir(const std::string& kind, } // Select an output directory. - if (const char* config_outdir = this->GetProperty(configProp)) { + if (cmProp config_outdir = this->GetProperty(configProp)) { // Use the user-specified per-configuration output directory. - out = cmGeneratorExpression::Evaluate(config_outdir, this->LocalGenerator, + out = cmGeneratorExpression::Evaluate(*config_outdir, this->LocalGenerator, config); // Skip per-configuration subdirectory. conf.clear(); - } else if (const char* outdir = this->GetProperty(propertyName)) { + } else if (cmProp outdir = this->GetProperty(propertyName)) { // Use the user-specified output directory. out = - cmGeneratorExpression::Evaluate(outdir, this->LocalGenerator, config); + cmGeneratorExpression::Evaluate(*outdir, this->LocalGenerator, config); // Skip per-configuration subdirectory if the value contained a // generator expression. - if (out != outdir) { + if (out != *outdir) { conf.clear(); } } @@ -5903,12 +6312,13 @@ bool cmGeneratorTarget::GetRPATH(const std::string& config, const std::string& prop, std::string& rpath) const { - const char* value = this->GetProperty(prop); + cmProp value = this->GetProperty(prop); if (!value) { return false; } - rpath = cmGeneratorExpression::Evaluate(value, this->LocalGenerator, config); + rpath = + cmGeneratorExpression::Evaluate(*value, this->LocalGenerator, config); return true; } @@ -5927,7 +6337,7 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( // An explicit list of interface libraries may be set for shared // libraries and executables that export symbols. - const char* explicitLibraries = nullptr; + cmProp explicitLibraries = nullptr; std::string linkIfaceProp; bool const cmp0022NEW = (this->GetPolicyStatusCMP0022() != cmPolicies::OLD && this->GetPolicyStatusCMP0022() != cmPolicies::WARN); @@ -5956,10 +6366,10 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( !this->PolicyWarnedCMP0022) { // Compare the explicitly set old link interface properties to the // preferred new link interface property one and warn if different. - const char* newExplicitLibraries = + cmProp newExplicitLibraries = this->GetProperty("INTERFACE_LINK_LIBRARIES"); if (newExplicitLibraries && - strcmp(newExplicitLibraries, explicitLibraries) != 0) { + (*newExplicitLibraries != *explicitLibraries)) { std::ostringstream w; /* clang-format off */ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n" @@ -5968,9 +6378,9 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( linkIfaceProp << " properties." "\n" "INTERFACE_LINK_LIBRARIES:\n" - " " << newExplicitLibraries << "\n" << + " " << *newExplicitLibraries << "\n" << linkIfaceProp << ":\n" - " " << explicitLibraries << "\n"; + " " << *explicitLibraries << "\n"; /* clang-format on */ this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING, w.str()); this->PolicyWarnedCMP0022 = true; @@ -5989,9 +6399,11 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( if (explicitLibraries) { // The interface libraries have been explicitly set. - this->ExpandLinkItems(linkIfaceProp, explicitLibraries, config, headTarget, - usage_requirements_only, iface.Libraries, - iface.HadHeadSensitiveCondition); + this->ExpandLinkItems(linkIfaceProp, *explicitLibraries, config, + headTarget, usage_requirements_only, iface.Libraries, + iface.HadHeadSensitiveCondition, + iface.HadContextSensitiveCondition, + 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 @@ -6009,11 +6421,15 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( // preferred new link interface property and warn if different. std::vector<cmLinkItem> ifaceLibs; static const std::string newProp = "INTERFACE_LINK_LIBRARIES"; - if (const char* newExplicitLibraries = this->GetProperty(newProp)) { + if (cmProp newExplicitLibraries = this->GetProperty(newProp)) { bool hadHeadSensitiveConditionDummy = false; - this->ExpandLinkItems(newProp, newExplicitLibraries, config, + bool hadContextSensitiveConditionDummy = false; + bool hadLinkLanguageSensitiveConditionDummy = false; + this->ExpandLinkItems(newProp, *newExplicitLibraries, config, headTarget, usage_requirements_only, ifaceLibs, - hadHeadSensitiveConditionDummy); + hadHeadSensitiveConditionDummy, + hadContextSensitiveConditionDummy, + hadLinkLanguageSensitiveConditionDummy); } if (ifaceLibs != iface.Libraries) { std::string oldLibraries = cmJoin(impl->Libraries, ";"); @@ -6050,19 +6466,22 @@ 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) { return nullptr; } - std::string CONFIG = cmSystemTools::UpperCase(config); cmHeadToLinkInterfaceMap& hm = (usage_requirements_only ? 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) { @@ -6076,7 +6495,9 @@ 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.HadContextSensitiveCondition, + iface.HadLinkLanguageSensitiveCondition); std::vector<std::string> deps = cmExpandedList(info->SharedDeps); this->LookupLinkItems(deps, cmListFileBacktrace(), iface.SharedDeps); } @@ -6132,17 +6553,17 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, // Initialize members. info.NoSOName = false; - const char* loc = nullptr; - const char* imp = nullptr; + cmProp loc = nullptr; + cmProp imp = nullptr; std::string suffix; - if (!this->Target->GetMappedConfig(desired_config, &loc, &imp, suffix)) { + if (!this->Target->GetMappedConfig(desired_config, loc, imp, suffix)) { return; } // Get the link interface. { std::string linkProp = "INTERFACE_LINK_LIBRARIES"; - const char* propertyLibs = this->GetProperty(linkProp); + cmProp propertyLibs = this->GetProperty(linkProp); if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { if (!propertyLibs) { @@ -6157,12 +6578,12 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, } if (propertyLibs) { info.LibrariesProp = linkProp; - info.Libraries = propertyLibs; + info.Libraries = *propertyLibs; } } if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) { if (loc) { - info.LibName = loc; + info.LibName = *loc; } return; } @@ -6172,47 +6593,46 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, // Get the location. if (loc) { - info.Location = loc; + info.Location = *loc; } else { std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix); - if (const char* config_location = this->GetProperty(impProp)) { - info.Location = config_location; - } else if (const char* location = this->GetProperty("IMPORTED_LOCATION")) { - info.Location = location; + if (cmProp config_location = this->GetProperty(impProp)) { + info.Location = *config_location; + } else if (cmProp location = this->GetProperty("IMPORTED_LOCATION")) { + info.Location = *location; } } // Get the soname. if (this->GetType() == cmStateEnums::SHARED_LIBRARY) { std::string soProp = cmStrCat("IMPORTED_SONAME", suffix); - if (const char* config_soname = this->GetProperty(soProp)) { - info.SOName = config_soname; - } else if (const char* soname = this->GetProperty("IMPORTED_SONAME")) { - info.SOName = soname; + if (cmProp config_soname = this->GetProperty(soProp)) { + info.SOName = *config_soname; + } else if (cmProp soname = this->GetProperty("IMPORTED_SONAME")) { + info.SOName = *soname; } } // Get the "no-soname" mark. if (this->GetType() == cmStateEnums::SHARED_LIBRARY) { std::string soProp = cmStrCat("IMPORTED_NO_SONAME", suffix); - if (const char* config_no_soname = this->GetProperty(soProp)) { - info.NoSOName = cmIsOn(config_no_soname); - } else if (const char* no_soname = - this->GetProperty("IMPORTED_NO_SONAME")) { - info.NoSOName = cmIsOn(no_soname); + if (cmProp config_no_soname = this->GetProperty(soProp)) { + info.NoSOName = cmIsOn(*config_no_soname); + } else if (cmProp no_soname = this->GetProperty("IMPORTED_NO_SONAME")) { + info.NoSOName = cmIsOn(*no_soname); } } // Get the import library. if (imp) { - info.ImportLibrary = imp; + info.ImportLibrary = *imp; } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->IsExecutableWithExports()) { std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix); - if (const char* config_implib = this->GetProperty(impProp)) { - info.ImportLibrary = config_implib; - } else if (const char* implib = this->GetProperty("IMPORTED_IMPLIB")) { - info.ImportLibrary = implib; + if (cmProp config_implib = this->GetProperty(impProp)) { + info.ImportLibrary = *config_implib; + } else if (cmProp implib = this->GetProperty("IMPORTED_IMPLIB")) { + info.ImportLibrary = *implib; } } @@ -6220,11 +6640,11 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, { std::string linkProp = cmStrCat("IMPORTED_LINK_DEPENDENT_LIBRARIES", suffix); - if (const char* config_libs = this->GetProperty(linkProp)) { - info.SharedDeps = config_libs; - } else if (const char* libs = + if (cmProp config_libs = this->GetProperty(linkProp)) { + info.SharedDeps = *config_libs; + } else if (cmProp libs = this->GetProperty("IMPORTED_LINK_DEPENDENT_LIBRARIES")) { - info.SharedDeps = libs; + info.SharedDeps = *libs; } } @@ -6232,21 +6652,21 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, if (this->LinkLanguagePropagatesToDependents()) { std::string linkProp = cmStrCat("IMPORTED_LINK_INTERFACE_LANGUAGES", suffix); - if (const char* config_libs = this->GetProperty(linkProp)) { - info.Languages = config_libs; - } else if (const char* libs = + if (cmProp config_libs = this->GetProperty(linkProp)) { + info.Languages = *config_libs; + } else if (cmProp libs = this->GetProperty("IMPORTED_LINK_INTERFACE_LANGUAGES")) { - info.Languages = libs; + info.Languages = *libs; } } // Get information if target is managed assembly. { std::string linkProp = "IMPORTED_COMMON_LANGUAGE_RUNTIME"; - if (auto pc = this->GetProperty(linkProp + suffix)) { - info.Managed = this->CheckManagedType(pc); - } else if (auto p = this->GetProperty(linkProp)) { - info.Managed = this->CheckManagedType(p); + if (cmProp pc = this->GetProperty(linkProp + suffix)) { + info.Managed = this->CheckManagedType(*pc); + } else if (cmProp p = this->GetProperty(linkProp)) { + info.Managed = this->CheckManagedType(*p); } } @@ -6254,11 +6674,11 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, if (this->GetType() == cmStateEnums::STATIC_LIBRARY) { std::string linkProp = cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix); - if (const char* config_reps = this->GetProperty(linkProp)) { - sscanf(config_reps, "%u", &info.Multiplicity); - } else if (const char* reps = + if (cmProp config_reps = this->GetProperty(linkProp)) { + sscanf(config_reps->c_str(), "%u", &info.Multiplicity); + } else if (cmProp reps = this->GetProperty("IMPORTED_LINK_INTERFACE_MULTIPLICITY")) { - sscanf(reps, "%u", &info.Multiplicity); + sscanf(reps->c_str(), "%u", &info.Multiplicity); } } } @@ -6266,28 +6686,36 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, cmHeadToLinkInterfaceMap& cmGeneratorTarget::GetHeadToLinkInterfaceMap( const std::string& config) const { - std::string CONFIG = cmSystemTools::UpperCase(config); - return this->LinkInterfaceMap[CONFIG]; + return this->LinkInterfaceMap[cmSystemTools::UpperCase(config)]; } cmHeadToLinkInterfaceMap& cmGeneratorTarget::GetHeadToLinkInterfaceUsageRequirementsMap( const std::string& config) const { - std::string CONFIG = cmSystemTools::UpperCase(config); - return this->LinkInterfaceUsageRequirementsOnlyMap[CONFIG]; + return this + ->LinkInterfaceUsageRequirementsOnlyMap[cmSystemTools::UpperCase(config)]; } 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; } - std::string CONFIG = cmSystemTools::UpperCase(config); - cmOptionalLinkImplementation& impl = this->LinkImplMap[CONFIG][this]; + cmOptionalLinkImplementation& impl = + this->LinkImplMap[cmSystemTools::UpperCase(config)][this]; + if (secondPass) { + impl = cmOptionalLinkImplementation(); + } if (!impl.LibrariesDone) { impl.LibrariesDone = true; this->ComputeLinkImplementationLibraries(config, impl, this); @@ -6426,15 +6854,15 @@ std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const bool cmGeneratorTarget::IsDeprecated() const { - const char* deprecation = this->GetProperty("DEPRECATION"); - return deprecation && *deprecation; + cmProp deprecation = this->GetProperty("DEPRECATION"); + return deprecation && !deprecation->empty(); } std::string cmGeneratorTarget::GetDeprecation() const { // find DEPRECATION property - if (const char* deprecation = this->GetProperty("DEPRECATION")) { - return deprecation; + if (cmProp deprecation = this->GetProperty("DEPRECATION")) { + return *deprecation; } return std::string(); } @@ -6491,9 +6919,9 @@ bool cmGeneratorTarget::IsCSharpOnly() const 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"); - if (linkLang && *linkLang) { - languages.insert(linkLang); + cmProp linkLang = this->GetProperty("LINKER_LANGUAGE"); + if (linkLang && !linkLang->empty()) { + languages.insert(*linkLang); } return languages.size() == 1 && languages.count("CSharp") > 0; } @@ -6543,8 +6971,8 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal( } // Populate the link implementation libraries for this configuration. - std::string CONFIG = cmSystemTools::UpperCase(config); - HeadToLinkImplementationMap& hm = this->LinkImplMap[CONFIG]; + HeadToLinkImplementationMap& hm = + this->LinkImplMap[cmSystemTools::UpperCase(config)]; // If the link implementation does not depend on the head target // then return the one we computed first. @@ -6563,7 +6991,7 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal( bool cmGeneratorTarget::IsNullImpliedByLinkLibraries( const std::string& p) const { - return cmContains(this->LinkImplicitNullProperties, p); + return cm::contains(this->LinkImplicitNullProperties, p); } void cmGeneratorTarget::ComputeLinkImplementationLibraries( @@ -6585,11 +7013,18 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( 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->GetHadContextSensitiveCondition()) { + impl.HadContextSensitiveCondition = true; + } + if (cge->GetHadLinkLanguageSensitiveCondition()) { + impl.HadLinkLanguageSensitiveCondition = true; + } for (std::string const& lib : llibs) { if (this->IsLinkLookupScope(lib, lg)) { @@ -6598,6 +7033,13 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( // Skip entries that resolve to the target itself or are empty. std::string name = this->CheckCMP0004(lib); + if (this->GetPolicyStatusCMP0108() == cmPolicies::NEW) { + // resolve alias name + auto target = this->Makefile->FindTargetToUse(name); + if (target) { + name = target->GetName(); + } + } if (name == this->GetName() || name.empty()) { if (name == this->GetName()) { bool noMessage = false; @@ -6867,8 +7309,8 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType( } // Check for explicitly set clr target property. - if (auto* clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) { - return this->CheckManagedType(clr); + if (cmProp clr = this->GetProperty("COMMON_LANGUAGE_RUNTIME")) { + return this->CheckManagedType(*clr); } // C# targets are always managed. This language specific check diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index d81bb3d85..3aedbf53e 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -18,6 +18,7 @@ #include "cmLinkItem.h" #include "cmListFileCache.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmStateTypes.h" class cmComputeLinkInformation; @@ -76,9 +77,9 @@ public: std::vector<std::string> GetPropertyKeys() const; //! Might return a nullptr if the property is not set or invalid - const char* GetProperty(const std::string& prop) const; + cmProp GetProperty(const std::string& prop) const; //! Always returns a valid pointer - const char* GetSafeProperty(const std::string& prop) const; + std::string const& GetSafeProperty(std::string const& prop) const; bool GetPropertyAsBool(const std::string& prop) const; void GetSourceFiles(std::vector<cmSourceFile*>& files, const std::string& config) const; @@ -115,9 +116,6 @@ public: struct KindedSources { std::vector<SourceAndKind> Sources; - std::set<std::string> ExpectedResxHeaders; - std::set<std::string> ExpectedXamlHeaders; - std::set<std::string> ExpectedXamlSources; bool Initialized = false; }; @@ -135,6 +133,9 @@ public: per-source configurations assigned. */ std::vector<AllConfigSource> const& GetAllConfigSources() const; + /** Get all sources needed for all configurations with given kind. */ + std::vector<AllConfigSource> GetAllConfigSources(SourceKind kind) const; + /** Get all languages used to compile sources in any configuration. This excludes the languages of objects from object libraries. */ std::set<std::string> GetAllConfigCompileLanguages() const; @@ -149,8 +150,6 @@ public: void GetModuleDefinitionSources(std::vector<cmSourceFile const*>&, const std::string& config) const; - void GetResxSources(std::vector<cmSourceFile const*>&, - const std::string& config) const; void GetExternalObjects(std::vector<cmSourceFile const*>&, const std::string& config) const; void GetHeaderSources(std::vector<cmSourceFile const*>&, @@ -159,20 +158,8 @@ public: const std::string& config) const; void GetCustomCommands(std::vector<cmSourceFile const*>&, const std::string& config) const; - void GetExpectedResxHeaders(std::set<std::string>&, - const std::string& config) const; - void GetAppManifest(std::vector<cmSourceFile const*>&, - const std::string& config) const; void GetManifests(std::vector<cmSourceFile const*>&, const std::string& config) const; - void GetCertificates(std::vector<cmSourceFile const*>&, - const std::string& config) const; - void GetXamlSources(std::vector<cmSourceFile const*>&, - const std::string& config) const; - void GetExpectedXamlHeaders(std::set<std::string>&, - const std::string& config) const; - void GetExpectedXamlSources(std::set<std::string>&, - const std::string& config) const; std::set<cmLinkItem> const& GetUtilityItems() const; @@ -204,6 +191,24 @@ public: const char* GetLinkInterfaceDependentNumberMaxProperty( const std::string& p, const std::string& config) const; + class DeviceLinkSetter + { + public: + DeviceLinkSetter(cmGeneratorTarget& target) + : Target(target) + { + this->PreviousState = target.SetDeviceLink(true); + } + ~DeviceLinkSetter() { this->Target.SetDeviceLink(this->PreviousState); }; + + private: + cmGeneratorTarget& Target; + bool PreviousState; + }; + + bool SetDeviceLink(bool deviceLink); + bool IsDeviceLink() const { return this->DeviceLink; } + cmLinkInterface const* GetLinkInterface( const std::string& config, const cmGeneratorTarget* headTarget) const; void ComputeLinkInterface(const std::string& config, @@ -225,7 +230,7 @@ public: /** Get the full path to the target according to the settings in its makefile and the configuration type. */ std::string GetFullPath( - const std::string& config = "", + const std::string& config, cmStateEnums::ArtifactType artifact = cmStateEnums::RuntimeBinaryArtifact, bool realname = false) const; std::string NormalGetFullPath(const std::string& config, @@ -263,7 +268,7 @@ public: /** Get the full name of the target according to the settings in its makefile. */ - std::string GetFullName(const std::string& config = "", + std::string GetFullName(const std::string& config, cmStateEnums::ArtifactType artifact = cmStateEnums::RuntimeBinaryArtifact) const; @@ -306,8 +311,7 @@ public: std::string GetSOName(const std::string& config) const; void GetFullNameComponents(std::string& prefix, std::string& base, - std::string& suffix, - const std::string& config = "", + std::string& suffix, const std::string& config, cmStateEnums::ArtifactType artifact = cmStateEnums::RuntimeBinaryArtifact) const; @@ -357,7 +361,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; @@ -422,6 +425,9 @@ public: void GetAppleArchs(const std::string& config, std::vector<std::string>& archVec) const; + void AddCUDAArchitectureFlags(std::string& flags) const; + void AddCUDAToolkitFlags(std::string& flags) const; + std::string GetFeatureSpecificLinkRuleVariable( std::string const& var, std::string const& lang, std::string const& config) const; @@ -479,17 +485,23 @@ public: const std::string& config, const std::string& language) const; std::string GetPchHeader(const std::string& config, - const std::string& language) const; + const std::string& language, + const std::string& arch = std::string()) const; std::string GetPchSource(const std::string& config, - const std::string& language) const; + const std::string& language, + const std::string& arch = std::string()) const; std::string GetPchFileObject(const std::string& config, - const std::string& language); + const std::string& language, + const std::string& arch = std::string()); std::string GetPchFile(const std::string& config, - const std::string& language); - std::string GetPchCreateCompileOptions(const std::string& config, - const std::string& language); + const std::string& language, + const std::string& arch = std::string()); + std::string GetPchCreateCompileOptions( + const std::string& config, const std::string& language, + const std::string& arch = std::string()); std::string GetPchUseCompileOptions(const std::string& config, - const std::string& language); + const std::string& language, + const std::string& arch = std::string()); void AddSourceFileToUnityBatch(const std::string& sourceFilename); bool IsSourceFilePartOfUnityBatch(const std::string& sourceFilename) const; @@ -513,7 +525,7 @@ public: configuration name is given then the generator will add its subdirectory for that configuration. Otherwise just the canonical output directory is given. */ - std::string GetDirectory(const std::string& config = "", + std::string GetDirectory(const std::string& config, cmStateEnums::ArtifactType artifact = cmStateEnums::RuntimeBinaryArtifact) const; @@ -521,7 +533,7 @@ public: If the configuration name is given then the generator will add its subdirectory for that configuration. Otherwise just the canonical compiler pdb output directory is given. */ - std::string GetCompilePDBDirectory(const std::string& config = "") const; + std::string GetCompilePDBDirectory(const std::string& config) const; /** Get sources that must be built before the given source. */ std::vector<cmSourceFile*> const* GetSourceDepends( @@ -550,7 +562,7 @@ public: std::string GetPDBOutputName(const std::string& config) const; /** Get the name of the pdb file for the target. */ - std::string GetPDBName(const std::string& config = "") const; + std::string GetPDBName(const std::string& config) const; /** Whether this library has soname enabled and platform supports it. */ bool HasSOName(const std::string& config) const; @@ -568,10 +580,10 @@ public: bool IsNullImpliedByLinkLibraries(const std::string& p) const; /** Get the name of the compiler pdb file for the target. */ - std::string GetCompilePDBName(const std::string& config = "") const; + std::string GetCompilePDBName(const std::string& config) const; /** Get the path for the MSVC /Fd option for this target. */ - std::string GetCompilePDBPath(const std::string& config = "") const; + std::string GetCompilePDBPath(const std::string& config) const; // Get the target base name. std::string GetOutputName(const std::string& config, @@ -589,6 +601,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. */ @@ -768,6 +783,9 @@ public: const std::string& fallback_property, int& major, int& minor, int& patch) const; + std::string GetRuntimeLinkLibrary(std::string const& lang, + std::string const& config) const; + std::string GetFortranModuleDirectory(std::string const& working_dir) const; const std::string& GetSourcesProperty() const; @@ -816,8 +834,10 @@ 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; + bool DeviceLink = false; // Returns ARCHIVE, LIBRARY, or RUNTIME based on platform and type. const char* GetOutputTargetType(cmStateEnums::ArtifactType artifact) const; @@ -850,6 +870,10 @@ private: 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; @@ -868,6 +892,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 { @@ -894,9 +929,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; @@ -940,7 +976,9 @@ private: const cmGeneratorTarget* headTarget, bool usage_requirements_only, std::vector<cmLinkItem>& items, - bool& hadHeadSensitiveCondition) const; + bool& hadHeadSensitiveCondition, + bool& hadContextSensitiveCondition, + bool& hadLinkLanguageSensitiveCondition) const; void LookupLinkItems(std::vector<std::string> const& names, cmListFileBacktrace const& bt, std::vector<cmLinkItem>& items) const; diff --git a/Source/cmGetCMakePropertyCommand.cxx b/Source/cmGetCMakePropertyCommand.cxx index ff4e312f3..79cbe443c 100644 --- a/Source/cmGetCMakePropertyCommand.cxx +++ b/Source/cmGetCMakePropertyCommand.cxx @@ -7,6 +7,7 @@ #include "cmExecutionStatus.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -23,25 +24,25 @@ bool cmGetCMakePropertyCommand(std::vector<std::string> const& args, std::string output = "NOTFOUND"; if (args[1] == "VARIABLES") { - if (const char* varsProp = status.GetMakefile().GetProperty("VARIABLES")) { - output = varsProp; + if (cmProp varsProp = status.GetMakefile().GetProperty("VARIABLES")) { + output = *varsProp; } } else if (args[1] == "MACROS") { output.clear(); - if (const char* macrosProp = status.GetMakefile().GetProperty("MACROS")) { - output = macrosProp; + if (cmProp macrosProp = status.GetMakefile().GetProperty("MACROS")) { + output = *macrosProp; } } else if (args[1] == "COMPONENTS") { const std::set<std::string>* components = status.GetMakefile().GetGlobalGenerator()->GetInstallComponents(); output = cmJoin(*components, ";"); } else { - const char* prop = nullptr; + cmProp prop = nullptr; if (!args[1].empty()) { prop = status.GetMakefile().GetState()->GetGlobalProperty(args[1]); } if (prop) { - output = prop; + output = *prop; } } diff --git a/Source/cmGetDirectoryPropertyCommand.cxx b/Source/cmGetDirectoryPropertyCommand.cxx index 64438d50a..fa4a40bef 100644 --- a/Source/cmGetDirectoryPropertyCommand.cxx +++ b/Source/cmGetDirectoryPropertyCommand.cxx @@ -7,7 +7,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" -#include "cmStringAlgorithms.h" +#include "cmProperty.h" #include "cmSystemTools.h" namespace { @@ -37,14 +37,8 @@ bool cmGetDirectoryPropertyCommand(std::vector<std::string> const& args, "DIRECTORY argument provided without subsequent arguments"); return false; } - std::string sd = *i; - // make sure the start dir is a full path - if (!cmSystemTools::FileIsFullPath(sd)) { - sd = cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', *i); - } - - // The local generators are associated with collapsed paths. - sd = cmSystemTools::CollapseFullPath(sd); + std::string sd = cmSystemTools::CollapseFullPath( + *i, status.GetMakefile().GetCurrentSourceDirectory()); // lookup the makefile from the directory name dir = status.GetMakefile().GetGlobalGenerator()->FindMakefile(sd); @@ -92,7 +86,9 @@ bool cmGetDirectoryPropertyCommand(std::vector<std::string> const& args, break; } } - prop = dir->GetProperty(*i); + if (cmProp p = dir->GetProperty(*i)) { + prop = p->c_str(); + } } StoreResult(status.GetMakefile(), variable, prop); return true; diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx index 7d91a7570..811421a6d 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/cmGetPipes.cxx b/Source/cmGetPipes.cxx index 4eda1c54a..a5b64692e 100644 --- a/Source/cmGetPipes.cxx +++ b/Source/cmGetPipes.cxx @@ -2,10 +2,9 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGetPipes.h" +#include <cm3p/uv.h> #include <fcntl.h> -#include "cm_uv.h" - #if defined(_WIN32) && !defined(__CYGWIN__) # include <io.h> diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx index 947d893db..cba770479 100644 --- a/Source/cmGetPropertyCommand.cxx +++ b/Source/cmGetPropertyCommand.cxx @@ -11,6 +11,7 @@ #include "cmPolicies.h" #include "cmProperty.h" #include "cmPropertyDefinition.h" +#include "cmSetPropertyCommand.h" #include "cmSourceFile.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -48,7 +49,9 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name, const std::string& propertyName); bool HandleSourceMode(cmExecutionStatus& status, const std::string& name, OutType infoType, const std::string& variable, - const std::string& propertyName); + const std::string& propertyName, + cmMakefile& directory_makefile, + bool source_file_paths_should_be_absolute); bool HandleTestMode(cmExecutionStatus& status, const std::string& name, OutType infoType, const std::string& variable, const std::string& propertyName); @@ -78,6 +81,11 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args, std::string name; std::string propertyName; + std::vector<std::string> source_file_directories; + std::vector<std::string> source_file_target_directories; + bool source_file_directory_option_enabled = false; + bool source_file_target_option_enabled = false; + // Get the scope from which to get the property. cmProperty::ScopeType scope; if (args[1] == "GLOBAL") { @@ -111,7 +119,9 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args, DoingNone, DoingName, DoingProperty, - DoingType + DoingType, + DoingSourceDirectory, + DoingSourceTargetDirectory }; Doing doing = DoingName; for (unsigned int i = 2; i < args.size(); ++i) { @@ -132,6 +142,20 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args, } else if (doing == DoingName) { doing = DoingNone; name = args[i]; + } else if (doing == DoingNone && scope == cmProperty::SOURCE_FILE && + args[i] == "DIRECTORY") { + doing = DoingSourceDirectory; + source_file_directory_option_enabled = true; + } else if (doing == DoingNone && scope == cmProperty::SOURCE_FILE && + args[i] == "TARGET_DIRECTORY") { + doing = DoingSourceTargetDirectory; + source_file_target_option_enabled = true; + } else if (doing == DoingSourceDirectory) { + source_file_directories.push_back(args[i]); + doing = DoingNone; + } else if (doing == DoingSourceTargetDirectory) { + source_file_target_directories.push_back(args[i]); + doing = DoingNone; } else if (doing == DoingProperty) { doing = DoingNone; propertyName = args[i]; @@ -147,6 +171,16 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args, return false; } + std::vector<cmMakefile*> source_file_directory_makefiles; + bool file_scopes_handled = + SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes( + status, source_file_directory_option_enabled, + source_file_target_option_enabled, source_file_directories, + source_file_target_directories, source_file_directory_makefiles); + if (!file_scopes_handled) { + return false; + } + // Compute requested output. if (infoType == OutBriefDoc) { // Lookup brief documentation. @@ -180,6 +214,11 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args, } } else { // Dispatch property getting. + cmMakefile& directory_scope_mf = *(source_file_directory_makefiles[0]); + bool source_file_paths_should_be_absolute = + source_file_directory_option_enabled || + source_file_target_option_enabled; + switch (scope) { case cmProperty::GLOBAL: return HandleGlobalMode(status, name, infoType, variable, @@ -191,8 +230,9 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args, return HandleTargetMode(status, name, infoType, variable, propertyName); case cmProperty::SOURCE_FILE: - return HandleSourceMode(status, name, infoType, variable, - propertyName); + return HandleSourceMode(status, name, infoType, variable, propertyName, + directory_scope_mf, + source_file_paths_should_be_absolute); case cmProperty::TEST: return HandleTestMode(status, name, infoType, variable, propertyName); case cmProperty::VARIABLE: @@ -241,8 +281,9 @@ bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name, // Get the property. cmake* cm = status.GetMakefile().GetCMakeInstance(); + cmProp p = cm->GetState()->GetGlobalProperty(propertyName); return StoreResult(infoType, status.GetMakefile(), variable, - cm->GetState()->GetGlobalProperty(propertyName)); + p ? p->c_str() : nullptr); } bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name, @@ -256,14 +297,8 @@ bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name, if (!name.empty()) { // Construct the directory name. Interpret relative paths with // respect to the current directory. - std::string dir = name; - if (!cmSystemTools::FileIsFullPath(dir)) { - dir = - cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', name); - } - - // The local generators are associated with collapsed paths. - dir = cmSystemTools::CollapseFullPath(dir); + std::string dir = cmSystemTools::CollapseFullPath( + name, status.GetMakefile().GetCurrentSourceDirectory()); // Lookup the generator. mf = status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir); @@ -294,8 +329,9 @@ bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name, } // Get the property. + cmProp p = mf->GetProperty(propertyName); return StoreResult(infoType, status.GetMakefile(), variable, - mf->GetProperty(propertyName)); + p ? p->c_str() : nullptr); } bool HandleTargetMode(cmExecutionStatus& status, const std::string& name, @@ -308,14 +344,24 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name, } if (cmTarget* target = status.GetMakefile().FindTargetToUse(name)) { - if (propertyName == "ALIASED_TARGET") { + if (propertyName == "ALIASED_TARGET" || propertyName == "ALIAS_GLOBAL") { if (status.GetMakefile().IsAlias(name)) { - return StoreResult(infoType, status.GetMakefile(), variable, - target->GetName().c_str()); + if (propertyName == "ALIASED_TARGET") { + + return StoreResult(infoType, status.GetMakefile(), variable, + target->GetName().c_str()); + } + if (propertyName == "ALIAS_GLOBAL") { + return StoreResult( + infoType, status.GetMakefile(), variable, + status.GetMakefile().GetGlobalGenerator()->IsAlias(name) + ? "TRUE" + : "FALSE"); + } } return StoreResult(infoType, status.GetMakefile(), variable, nullptr); } - const char* prop_cstr = nullptr; + cmProp prop_cstr = nullptr; cmListFileBacktrace bt = status.GetMakefile().GetBacktrace(); cmMessenger* messenger = status.GetMakefile().GetMessenger(); if (cmTargetPropertyComputer::PassesWhitelist( @@ -325,7 +371,8 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name, prop_cstr = target->GetProperty(propertyName); } } - return StoreResult(infoType, status.GetMakefile(), variable, prop_cstr); + return StoreResult(infoType, status.GetMakefile(), variable, + prop_cstr ? prop_cstr->c_str() : nullptr); } status.SetError(cmStrCat("could not find TARGET ", name, ". Perhaps it has not yet been created.")); @@ -334,7 +381,9 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name, bool HandleSourceMode(cmExecutionStatus& status, const std::string& name, OutType infoType, const std::string& variable, - const std::string& propertyName) + const std::string& propertyName, + cmMakefile& directory_makefile, + const bool source_file_paths_should_be_absolute) { if (name.empty()) { status.SetError("not given name for SOURCE scope."); @@ -342,12 +391,17 @@ bool HandleSourceMode(cmExecutionStatus& status, const std::string& name, } // Get the source file. - if (cmSourceFile* sf = status.GetMakefile().GetOrCreateSource(name)) { + const std::string source_file_absolute_path = + SetPropertyCommand::MakeSourceFilePathAbsoluteIfNeeded( + status, name, source_file_paths_should_be_absolute); + if (cmSourceFile* sf = + directory_makefile.GetOrCreateSource(source_file_absolute_path)) { return StoreResult(infoType, status.GetMakefile(), variable, sf->GetPropertyForUser(propertyName)); } status.SetError( - cmStrCat("given SOURCE name that could not be found or created: ", name)); + cmStrCat("given SOURCE name that could not be found or created: ", + source_file_absolute_path)); return false; } @@ -393,12 +447,13 @@ bool HandleCacheMode(cmExecutionStatus& status, const std::string& name, return false; } - const char* value = nullptr; + cmProp value = nullptr; if (status.GetMakefile().GetState()->GetCacheEntryValue(name)) { value = status.GetMakefile().GetState()->GetCacheEntryProperty( name, propertyName); } - StoreResult(infoType, status.GetMakefile(), variable, value); + StoreResult(infoType, status.GetMakefile(), variable, + value ? value->c_str() : nullptr); return true; } diff --git a/Source/cmGetSourceFilePropertyCommand.cxx b/Source/cmGetSourceFilePropertyCommand.cxx index eefdc6ccb..5395bc8ef 100644 --- a/Source/cmGetSourceFilePropertyCommand.cxx +++ b/Source/cmGetSourceFilePropertyCommand.cxx @@ -4,35 +4,71 @@ #include "cmExecutionStatus.h" #include "cmMakefile.h" +#include "cmSetPropertyCommand.h" #include "cmSourceFile.h" bool cmGetSourceFilePropertyCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { - if (args.size() != 3) { + std::vector<std::string>::size_type args_size = args.size(); + if (args_size != 3 && args_size != 5) { status.SetError("called with incorrect number of arguments"); return false; } + + std::vector<std::string> source_file_directories; + std::vector<std::string> source_file_target_directories; + bool source_file_directory_option_enabled = false; + bool source_file_target_option_enabled = false; + + int property_arg_index = 2; + if (args[2] == "DIRECTORY" && args_size == 5) { + property_arg_index = 4; + source_file_directory_option_enabled = true; + source_file_directories.push_back(args[3]); + } else if (args[2] == "TARGET_DIRECTORY" && args_size == 5) { + property_arg_index = 4; + source_file_target_option_enabled = true; + source_file_target_directories.push_back(args[3]); + } + + std::vector<cmMakefile*> source_file_directory_makefiles; + bool file_scopes_handled = + SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes( + status, source_file_directory_option_enabled, + source_file_target_option_enabled, source_file_directories, + source_file_target_directories, source_file_directory_makefiles); + if (!file_scopes_handled) { + return false; + } + std::string const& var = args[0]; - std::string const& file = args[1]; - cmMakefile& mf = status.GetMakefile(); + bool source_file_paths_should_be_absolute = + source_file_directory_option_enabled || source_file_target_option_enabled; + std::string const file = + SetPropertyCommand::MakeSourceFilePathAbsoluteIfNeeded( + status, args[1], source_file_paths_should_be_absolute); + cmMakefile& mf = *source_file_directory_makefiles[0]; cmSourceFile* sf = mf.GetSource(file); // for the location we must create a source file first - if (!sf && args[2] == "LOCATION") { + if (!sf && args[property_arg_index] == "LOCATION") { sf = mf.CreateSource(file); } + if (sf) { const char* prop = nullptr; - if (!args[2].empty()) { - prop = sf->GetPropertyForUser(args[2]); + if (!args[property_arg_index].empty()) { + prop = sf->GetPropertyForUser(args[property_arg_index]); } if (prop) { - mf.AddDefinition(var, prop); + // Set the value on the original Makefile scope, not the scope of the + // requested directory. + status.GetMakefile().AddDefinition(var, prop); return true; } } - mf.AddDefinition(var, "NOTFOUND"); + status.GetMakefile().AddDefinition(var, "NOTFOUND"); return true; } diff --git a/Source/cmGetTargetPropertyCommand.cxx b/Source/cmGetTargetPropertyCommand.cxx index 7f5df9cfb..8a304be0d 100644 --- a/Source/cmGetTargetPropertyCommand.cxx +++ b/Source/cmGetTargetPropertyCommand.cxx @@ -5,10 +5,12 @@ #include <sstream> #include "cmExecutionStatus.h" +#include "cmGlobalGenerator.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmTarget.h" #include "cmTargetPropertyComputer.h" @@ -28,13 +30,20 @@ bool cmGetTargetPropertyCommand(std::vector<std::string> const& args, cmMakefile& mf = status.GetMakefile(); if (cmTarget* tgt = mf.FindTargetToUse(targetName)) { - if (args[2] == "ALIASED_TARGET") { + if (args[2] == "ALIASED_TARGET" || args[2] == "ALIAS_GLOBAL") { if (mf.IsAlias(targetName)) { - prop = tgt->GetName(); prop_exists = true; + if (args[2] == "ALIASED_TARGET") { + + prop = tgt->GetName(); + } + if (args[2] == "ALIAS_GLOBAL") { + prop = + mf.GetGlobalGenerator()->IsAlias(targetName) ? "TRUE" : "FALSE"; + } } } else if (!args[2].empty()) { - const char* prop_cstr = nullptr; + cmProp prop_cstr = nullptr; cmListFileBacktrace bt = mf.GetBacktrace(); cmMessenger* messenger = mf.GetMessenger(); if (cmTargetPropertyComputer::PassesWhitelist(tgt->GetType(), args[2], @@ -45,7 +54,7 @@ bool cmGetTargetPropertyCommand(std::vector<std::string> const& args, } } if (prop_cstr) { - prop = prop_cstr; + prop = *prop_cstr; prop_exists = true; } } diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index 5e2248ed1..358d65a8c 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -14,11 +14,12 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalGhsMultiGenerator.h" -#include "cmLinkLineComputer.h" +#include "cmLinkLineComputer.h" // IWYU pragma: keep #include "cmLocalGenerator.h" #include "cmLocalGhsMultiGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmSourceFile.h" #include "cmSourceFileLocation.h" #include "cmSourceGroup.h" @@ -165,13 +166,15 @@ void cmGhsMultiTargetGenerator::WriteTargetSpecifics(std::ostream& fout, outpath = this->GeneratorTarget->GetDirectory(config); outpath = this->LocalGenerator->MaybeConvertToRelativePath(rootpath, outpath); - fout << " :binDirRelative=\"" << outpath << "\"" << std::endl; - fout << " -o \"" << this->TargetNameReal << "\"" << std::endl; + /* clang-format off */ + fout << " :binDirRelative=\"" << outpath << "\"\n" + " -o \"" << this->TargetNameReal << "\"\n"; + /* clang-format on */ } // set target object file destination outpath = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - fout << " :outputDirRelative=\"" << outpath << "\"" << std::endl; + fout << " :outputDirRelative=\"" << outpath << "\"\n"; } void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config, @@ -180,15 +183,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 +197,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 +211,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,8 +234,8 @@ void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream& fout, if (!flagsByLangI->second.empty()) { std::vector<std::string> ghsCompFlags = cmSystemTools::ParseArguments(flagsByLangI->second); - for (auto& f : ghsCompFlags) { - fout << " " << f << std::endl; + for (const std::string& f : ghsCompFlags) { + fout << " " << f << '\n'; } } } @@ -249,7 +248,7 @@ void cmGhsMultiTargetGenerator::WriteCompilerDefinitions( this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config, language); for (std::string const& compileDefinition : compileDefinitions) { - fout << " -D" << compileDefinition << std::endl; + fout << " -D" << compileDefinition << '\n'; } } @@ -262,7 +261,7 @@ void cmGhsMultiTargetGenerator::WriteIncludes(std::ostream& fout, language, config); for (std::string const& include : includes) { - fout << " -I\"" << include << "\"" << std::endl; + fout << " -I\"" << include << "\"\n"; } } @@ -290,15 +289,15 @@ void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout, // write out link options std::vector<std::string> lopts = cmSystemTools::ParseArguments(linkFlags); - for (auto& l : lopts) { - fout << " " << l << std::endl; + for (const std::string& l : lopts) { + fout << " " << l << '\n'; } // 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) { - fout << " -L\"" << l << "\"" << std::endl; + for (const std::string& l : lpath) { + fout << " -L\"" << l << "\"\n"; } // write out link libs @@ -307,12 +306,12 @@ 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; + fout << " \"" << l << "\"\n"; } else { std::string rl = cmSystemTools::CollapseFullPath(l, cbd); - fout << " -l\"" << rl << "\"" << std::endl; + fout << " -l\"" << rl << "\"\n"; } } } @@ -353,13 +352,12 @@ void cmGhsMultiTargetGenerator::WriteBuildEventsHelper( this->WriteCustomCommandsHelper(f, ccg); f.Close(); if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) { - fout << " :" << cmd << "=\"" << fname << "\"" << std::endl; + fout << " :" << cmd << "=\"" << fname << "\"\n"; } else { - fout << fname << std::endl; - fout << " :outputName=\"" << fname << ".rule\"" << std::endl; + fout << fname << "\n :outputName=\"" << fname << ".rule\"\n"; } for (auto& byp : ccg.GetByproducts()) { - fout << " :extraOutputFile=\"" << byp << "\"" << std::endl; + fout << " :extraOutputFile=\"" << byp << "\"\n"; } } } @@ -451,8 +449,7 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper( // push back the custom commands for (auto const& c : cmdLines) { - fout << c << std::endl; - fout << check_error << std::endl; + fout << c << '\n' << check_error << '\n'; } } @@ -460,11 +457,11 @@ void cmGhsMultiTargetGenerator::WriteSourceProperty( std::ostream& fout, const cmSourceFile* sf, std::string const& propName, std::string const& propFlag) { - const char* prop = sf->GetProperty(propName); + cmProp prop = sf->GetProperty(propName); if (prop) { - std::vector<std::string> list = cmExpandedList(prop); - for (auto& p : list) { - fout << " " << propFlag << p << std::endl; + std::vector<std::string> list = cmExpandedList(*prop); + for (const std::string& p : list) { + fout << " " << propFlag << p << '\n'; } } } @@ -483,7 +480,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(); @@ -553,8 +550,8 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj) */ for (auto& sg : groupFilesList) { std::ostream* fout; - bool useProjectFile = - cmIsOn(this->GeneratorTarget->GetProperty("GHS_NO_SOURCE_GROUP_FILE")) || + bool useProjectFile = cmIsOn(*this->GeneratorTarget->GetProperty( + "GHS_NO_SOURCE_GROUP_FILE")) || cmIsOn(this->Makefile->GetDefinition("CMAKE_GHS_NO_SOURCE_GROUP_FILE")); if (useProjectFile || sg.empty()) { fout = &fout_proj; @@ -579,12 +576,12 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj) if (useProjectFile) { if (sg.empty()) { - *fout << "{comment} Others" << std::endl; + *fout << "{comment} Others" << '\n'; } else { - *fout << "{comment} " << sg << std::endl; + *fout << "{comment} " << sg << '\n'; } } else if (sg.empty()) { - *fout << "{comment} Others" << std::endl; + *fout << "{comment} Others\n"; } if (sg != "CMake Rules") { @@ -612,7 +609,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj) compile = false; } - *fout << comment << fname << std::endl; + *fout << comment << fname << '\n'; if (compile) { if ("ld" != si->GetExtension() && "int" != si->GetExtension() && "bsp" != si->GetExtension()) { @@ -628,7 +625,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj) std::string objectName = this->GeneratorTarget->GetObjectName(si); if (!objectName.empty() && this->GeneratorTarget->HasExplicitObjectName(si)) { - *fout << " -o " << objectName << std::endl; + *fout << " -o " << objectName << '\n'; } } } @@ -695,14 +692,14 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandLine( */ bool specifyExtra = true; for (auto& out : ccg.GetOutputs()) { - fout << fname << std::endl; - fout << " :outputName=\"" << out << "\"" << std::endl; + fout << fname << '\n'; + fout << " :outputName=\"" << out << "\"\n"; if (specifyExtra) { for (auto& byp : ccg.GetByproducts()) { - fout << " :extraOutputFile=\"" << byp << "\"" << std::endl; + fout << " :extraOutputFile=\"" << byp << "\"\n"; } for (auto& dep : ccg.GetDepends()) { - fout << " :depends=\"" << dep << "\"" << std::endl; + fout << " :depends=\"" << dep << "\"\n"; } specifyExtra = false; } @@ -712,25 +709,25 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandLine( void cmGhsMultiTargetGenerator::WriteObjectLangOverride( std::ostream& fout, const cmSourceFile* sourceFile) { - const char* rawLangProp = sourceFile->GetProperty("LANGUAGE"); + cmProp rawLangProp = sourceFile->GetProperty("LANGUAGE"); if (nullptr != rawLangProp) { - std::string sourceLangProp(rawLangProp); + std::string sourceLangProp(*rawLangProp); std::string const& extension = sourceFile->GetExtension(); if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) { - fout << " -dotciscxx" << std::endl; + fout << " -dotciscxx\n"; } } } bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp() { - const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app"); + cmProp p = this->GeneratorTarget->GetProperty("ghs_integrity_app"); if (p) { - return cmIsOn(this->GeneratorTarget->GetProperty("ghs_integrity_app")); + return cmIsOn(*p); } 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/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h index 9af0eac41..3c979550c 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.h +++ b/Source/cmGlobalBorlandMakefileGenerator.h @@ -46,6 +46,7 @@ public: bool AllowNotParallel() const override { return false; } bool AllowDeleteOnError() const override { return false; } + bool CanEscapeOctothorpe() const override { return true; } protected: std::vector<GeneratedMakeCommand> GenerateBuildCommand( diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx index e04eef1b4..9dc86f4e4 100644 --- a/Source/cmGlobalCommonGenerator.cxx +++ b/Source/cmGlobalCommonGenerator.cxx @@ -7,6 +7,7 @@ #include "cmGeneratorTarget.h" #include "cmLocalGenerator.h" +#include "cmProperty.h" #include "cmStateDirectory.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" @@ -45,8 +46,8 @@ cmGlobalCommonGenerator::ComputeDirectoryTargets() const } DirectoryTarget::Target t; t.GT = gt.get(); - if (const char* exclude = gt->GetProperty("EXCLUDE_FROM_ALL")) { - if (cmIsOn(exclude)) { + if (cmProp exclude = gt->GetProperty("EXCLUDE_FROM_ALL")) { + if (cmIsOn(*exclude)) { // This target has been explicitly excluded. t.ExcludeFromAll = true; } else { diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 238097d04..4dc409221 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -14,6 +14,7 @@ #include <utility> #include <cm/memory> +#include <cmext/algorithm> #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" @@ -41,6 +42,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmSourceFile.h" #include "cmState.h" @@ -51,8 +53,8 @@ #include "cmake.h" #if !defined(CMAKE_BOOTSTRAP) -# include "cm_jsoncpp_value.h" -# include "cm_jsoncpp_writer.h" +# include <cm3p/json/value.h> +# include <cm3p/json/writer.h> # include "cmCryptoHash.h" # include "cmQtAutoGenGlobalInitializer.h" @@ -231,7 +233,7 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang, if (!optional && (path.empty() || !cmSystemTools::FileExists(path))) { return; } - const std::string* cname = + cmProp cname = this->GetCMakeInstance()->GetState()->GetInitializedCacheValue(langComp); std::string changeVars; if (cname && !optional) { @@ -246,11 +248,10 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang, cmSystemTools::ConvertToUnixSlashes(cnameString); cmSystemTools::ConvertToUnixSlashes(pathString); if (cnameString != pathString) { - const char* cvars = - this->GetCMakeInstance()->GetState()->GetGlobalProperty( - "__CMAKE_DELETE_CACHE_CHANGE_VARS_"); + cmProp cvars = this->GetCMakeInstance()->GetState()->GetGlobalProperty( + "__CMAKE_DELETE_CACHE_CHANGE_VARS_"); if (cvars) { - changeVars += cvars; + changeVars += *cvars; changeVars += ";"; } changeVars += langComp; @@ -303,10 +304,14 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const for (const auto& target : localGen->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET || target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY || - target->GetType() == cmStateEnums::TargetType::UTILITY || - cmIsOn(target->GetProperty("ghs_integrity_app"))) { + target->GetType() == cmStateEnums::TargetType::UTILITY) { continue; } + if (cmProp p = target->GetProperty("ghs_integrity_app")) { + if (cmIsOn(*p)) { + continue; + } + } std::vector<std::string> configs; target->Makefile->GetConfigurations(configs); @@ -316,7 +321,7 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const } else { for (std::string const& config : configs) { target->GetSourceFiles(srcs, config); - if (srcs.empty()) { + if (!srcs.empty()) { break; } } @@ -371,14 +376,18 @@ bool cmGlobalGenerator::CheckTargetsForPchCompilePdb() const for (const auto& target : generator->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET || target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY || - target->GetType() == cmStateEnums::TargetType::UTILITY || - cmIsOn(target->GetProperty("ghs_integrity_app"))) { + target->GetType() == cmStateEnums::TargetType::UTILITY) { continue; } + if (cmProp p = target->GetProperty("ghs_integrity_app")) { + if (cmIsOn(*p)) { + continue; + } + } - const std::string reuseFrom = + std::string const& reuseFrom = target->GetSafeProperty("PRECOMPILE_HEADERS_REUSE_FROM"); - const std::string compilePdb = + std::string const& compilePdb = target->GetSafeProperty("COMPILE_PDB_NAME"); if (!reuseFrom.empty() && reuseFrom != compilePdb) { @@ -404,7 +413,7 @@ bool cmGlobalGenerator::IsExportedTargetsFile( if (it == this->BuildExportSets.end()) { return false; } - return !cmContains(this->BuildExportExportSets, filename); + return !cm::contains(this->BuildExportExportSets, filename); } // Find the make program for the generator, required for try compiles @@ -445,8 +454,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; } @@ -530,7 +539,7 @@ void cmGlobalGenerator::EnableLanguage( if (lang == "NONE") { this->SetLanguageEnabled("NONE", mf); } else { - if (!cmContains(this->LanguagesReady, lang)) { + if (!cm::contains(this->LanguagesReady, lang)) { std::ostringstream e; e << "The test project needs language " << lang << " which is not enabled."; @@ -1095,7 +1104,7 @@ void cmGlobalGenerator::SetLanguageEnabledMaps(const std::string& l, { // use LanguageToLinkerPreference to detect whether this functions has // run before - if (cmContains(this->LanguageToLinkerPreference, l)) { + if (cm::contains(this->LanguageToLinkerPreference, l)) { return; } @@ -1418,13 +1427,13 @@ bool cmGlobalGenerator::Compute() // so create the map from project name to vector of local generators this->FillProjectMap(); - // Iterate through all targets and set up AUTOMOC, AUTOUIC and AUTORCC - if (!this->QtAutoGen()) { + // Add automatically generated sources (e.g. unity build). + if (!this->AddAutomaticSources()) { return false; } - // Add automatically generated sources (e.g. unity build). - if (!this->AddAutomaticSources()) { + // Iterate through all targets and set up AUTOMOC, AUTOUIC and AUTORCC + if (!this->QtAutoGen()) { return false; } @@ -1695,8 +1704,8 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo() for (std::string const& c : configs) { std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(c)); - if (const char* val = mf->GetProperty(defPropName)) { - t->AppendProperty(defPropName, val); + if (cmProp val = mf->GetProperty(defPropName)) { + t->AppendProperty(defPropName, *val); } } } @@ -1807,14 +1816,13 @@ void cmGlobalGenerator::CheckTargetProperties() } } std::vector<std::string> incs; - const char* incDirProp = - target.second.GetProperty("INCLUDE_DIRECTORIES"); + cmProp incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES"); if (!incDirProp) { continue; } std::string incDirs = cmGeneratorExpression::Preprocess( - incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions); + *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions); cmExpandList(incDirs, incs); @@ -2066,9 +2074,8 @@ void cmGlobalGenerator::AddMakefile(std::unique_ptr<cmMakefile> mf) // update progress // estimate how many lg there will be - const std::string* numGenC = - this->CMakeInstance->GetState()->GetInitializedCacheValue( - "CMAKE_NUMBER_OF_MAKEFILES"); + cmProp numGenC = this->CMakeInstance->GetState()->GetInitializedCacheValue( + "CMAKE_NUMBER_OF_MAKEFILES"); if (!numGenC) { // If CMAKE_NUMBER_OF_MAKEFILES is not set @@ -2177,8 +2184,8 @@ bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root, if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { return true; } - if (const char* exclude = target->GetProperty("EXCLUDE_FROM_ALL")) { - return cmIsOn(exclude); + if (cmProp exclude = target->GetProperty("EXCLUDE_FROM_ALL")) { + return cmIsOn(*exclude); } // This target is included in its directory. Check whether the // directory is excluded. @@ -2245,7 +2252,7 @@ void cmGlobalGenerator::AddAlias(const std::string& name, bool cmGlobalGenerator::IsAlias(const std::string& name) const { - return cmContains(this->AliasTargets, name); + return cm::contains(this->AliasTargets, name); } void cmGlobalGenerator::IndexTarget(cmTarget* t) @@ -2271,10 +2278,12 @@ std::string cmGlobalGenerator::IndexGeneratorTargetUniquely( // Use a ":" prefix to avoid conflict with project-defined targets. // We must satisfy cmGeneratorExpression::IsValidTargetName so use no // other special characters. - char buf[1 + sizeof(gt) * 2]; + constexpr size_t sizeof_ptr = + sizeof(gt); // NOLINT(bugprone-sizeof-expression) + char buf[1 + sizeof_ptr * 2]; char* b = buf; *b++ = ':'; - for (size_t i = 0; i < sizeof(gt); ++i) { + for (size_t i = 0; i < sizeof_ptr; ++i) { unsigned char const c = reinterpret_cast<unsigned char const*>(>)[i]; *b++ = hexDigits[(c & 0xf0) >> 4]; *b++ = hexDigits[(c & 0x0f)]; @@ -2515,9 +2524,8 @@ 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); + std::vector<std::string> args; + if (mf->GetDefExpandList("CMAKE_CTEST_ARGUMENTS", args)) { for (auto const& arg : args) { singleLine.push_back(arg); } @@ -2543,7 +2551,7 @@ void cmGlobalGenerator::AddGlobalTarget_EditCache( } GlobalTargetInfo gti; gti.Name = editCacheTargetName; - gti.PerConfig = false; + gti.PerConfig = cmTarget::PerConfig::No; cmCustomCommandLine singleLine; // Use generator preference for the edit_cache rule if it is defined. @@ -2561,6 +2569,7 @@ void cmGlobalGenerator::AddGlobalTarget_EditCache( singleLine.push_back("No interactive CMake dialog available."); gti.Message = "No interactive CMake dialog available..."; gti.UsesTerminal = false; + gti.StdPipesUTF8 = true; } gti.CommandLines.push_back(std::move(singleLine)); @@ -2578,13 +2587,14 @@ void cmGlobalGenerator::AddGlobalTarget_RebuildCache( gti.Name = rebuildCacheTargetName; gti.Message = "Running CMake to regenerate build system..."; gti.UsesTerminal = true; - gti.PerConfig = false; + gti.PerConfig = cmTarget::PerConfig::No; cmCustomCommandLine singleLine; singleLine.push_back(cmSystemTools::GetCMakeCommand()); singleLine.push_back("--regenerate-during-build"); singleLine.push_back("-S$(CMAKE_SOURCE_DIR)"); singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); gti.CommandLines.push_back(std::move(singleLine)); + gti.StdPipesUTF8 = true; targets.push_back(std::move(gti)); } @@ -2621,6 +2631,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install( gti.Name = this->GetInstallTargetName(); gti.Message = "Install the project..."; gti.UsesTerminal = true; + gti.StdPipesUTF8 = true; cmCustomCommandLine singleLine; if (this->GetPreinstallTargetName()) { gti.Depends.emplace_back(this->GetPreinstallTargetName()); @@ -2690,13 +2701,13 @@ void cmGlobalGenerator::AddGlobalTarget_Install( } } -const char* cmGlobalGenerator::GetPredefinedTargetsFolder() +std::string cmGlobalGenerator::GetPredefinedTargetsFolder() { - const char* prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty( + cmProp prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty( "PREDEFINED_TARGETS_FOLDER"); if (prop) { - return prop; + return *prop; } return "CMakePredefinedTargets"; @@ -2704,13 +2715,13 @@ const char* cmGlobalGenerator::GetPredefinedTargetsFolder() bool cmGlobalGenerator::UseFolderProperty() const { - const char* prop = + cmProp prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS"); // If this property is defined, let the setter turn this on or off... // if (prop) { - return cmIsOn(prop); + return cmIsOn(*prop); } // By default, this feature is OFF, since it is not supported in the @@ -2732,7 +2743,8 @@ cmTarget cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti, std::vector<std::string> no_depends; // Store the custom command in the target. cmCustomCommand cc(no_outputs, no_byproducts, no_depends, gti.CommandLines, - cmListFileBacktrace(), nullptr, gti.WorkingDir.c_str()); + cmListFileBacktrace(), nullptr, gti.WorkingDir.c_str(), + gti.StdPipesUTF8); cc.SetUsesTerminal(gti.UsesTerminal); target.AddPostBuildCommand(std::move(cc)); if (!gti.Message.empty()) { @@ -2804,7 +2816,7 @@ bool cmGlobalGenerator::IsReservedTarget(std::string const& name) "clean", "edit_cache", "rebuild_cache", "ZERO_CHECK" }; - return cmContains(reservedTargets, name); + return cm::contains(reservedTargets, name); } void cmGlobalGenerator::SetExternalMakefileProjectGenerator( @@ -3051,8 +3063,8 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target) #ifndef CMAKE_BOOTSTRAP // Check whether labels are enabled for this target. - const char* targetLabels = target->GetProperty("LABELS"); - const char* directoryLabels = + cmProp targetLabels = target->GetProperty("LABELS"); + cmProp directoryLabels = target->Target->GetMakefile()->GetProperty("LABELS"); const char* cmakeDirectoryLabels = target->Target->GetMakefile()->GetDefinition("CMAKE_DIRECTORY_LABELS"); @@ -3071,7 +3083,7 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target) // List the target-wide labels. All sources in the target get // these labels. if (targetLabels) { - cmExpandList(targetLabels, labels); + cmExpandList(*targetLabels, labels); if (!labels.empty()) { fout << "# Target labels\n"; for (std::string const& l : labels) { @@ -3086,7 +3098,7 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target) std::vector<std::string> cmakeDirectoryLabelsList; if (directoryLabels) { - cmExpandList(directoryLabels, directoryLabelsList); + cmExpandList(*directoryLabels, directoryLabelsList); } if (cmakeDirectoryLabels) { @@ -3121,10 +3133,10 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target) std::string const& sfp = sf->ResolveFullPath(); fout << sfp << "\n"; lj_source["file"] = sfp; - if (const char* svalue = sf->GetProperty("LABELS")) { + if (cmProp svalue = sf->GetProperty("LABELS")) { labels.clear(); Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue; - cmExpandList(svalue, labels); + cmExpandList(*svalue, labels); for (std::string const& label : labels) { fout << " " << label << "\n"; lj_source_labels.append(label); diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 7dc482238..57c780807 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -28,7 +28,7 @@ #include "cmTargetDepend.h" #if !defined(CMAKE_BOOTSTRAP) -# include "cm_jsoncpp_value.h" +# include <cm3p/json/value.h> # include "cmFileLockPool.h" #endif @@ -553,7 +553,8 @@ protected: std::vector<std::string> Depends; std::string WorkingDir; bool UsesTerminal = false; - bool PerConfig = true; + cmTarget::PerConfig PerConfig = cmTarget::PerConfig::Yes; + bool StdPipesUTF8 = false; }; void CreateDefaultGlobalTargets(std::vector<GlobalTargetInfo>& targets); @@ -588,7 +589,7 @@ protected: cmGeneratorTarget* FindGeneratorTargetImpl(std::string const& name) const; - const char* GetPredefinedTargetsFolder(); + std::string GetPredefinedTargetsFolder(); private: using TargetMap = std::unordered_map<std::string, cmTarget*>; diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index bb9dd3734..d36adfb74 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -9,8 +9,9 @@ #include <utility> #include <cm/memory> +#include <cm/string> +#include <cmext/algorithm> -#include "cmAlgorithms.h" #include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" @@ -18,6 +19,7 @@ #include "cmLocalGenerator.h" #include "cmLocalGhsMultiGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -90,7 +92,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); } @@ -112,8 +114,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); @@ -132,7 +134,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 { @@ -166,7 +168,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( @@ -253,14 +255,15 @@ void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd, void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout) { - fout << "#!gbuild" << std::endl; - fout << "#" << std::endl - << "# CMAKE generated file: DO NOT EDIT!" << std::endl - << "# Generated by \"" << GetActualName() << "\"" - << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "." - << cmVersion::GetMinorVersion() << std::endl - << "#" << std::endl - << std::endl; + /* clang-format off */ + fout << "#!gbuild\n" + "#\n" + "# CMAKE generated file: DO NOT EDIT!\n" + "# Generated by \"" << GetActualName() << "\"" + " Generator, CMake Version " << cmVersion::GetMajorVersion() << '.' + << cmVersion::GetMinorVersion() << "\n" + "#\n\n"; + /* clang-format on */ } void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream& fout) @@ -268,36 +271,36 @@ void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream& fout) fout << "Commands {\n" " Custom_Rule_Command {\n" " name = \"Custom Rule Command\"\n" - " exec = \""; + " exec = \"" #ifdef _WIN32 - fout << "cmd.exe"; + "cmd.exe" #else - fout << "/bin/sh"; + "/bin/sh" #endif - fout << "\"\n" + "\"\n" " options = {\"SpecialOptions\"}\n" " }\n" - "}\n"; + "}\n" - fout << "\n\n"; - fout << "FileTypes {\n" + "\n\n" + "FileTypes {\n" " CmakeRule {\n" " name = \"Custom Rule\"\n" " action = \"&Run\"\n" - " extensions = {\""; + " extensions = {\"" #ifdef _WIN32 - fout << "bat"; + "bat" #else - fout << "sh"; + "sh" #endif - fout << "\"}\n" + "\"}\n" " grepable = false\n" " command = \"Custom Rule Command\"\n" - " commandLine = \"$COMMAND "; + " commandLine = \"$COMMAND " #ifdef _WIN32 - fout << "/c"; + "/c" #endif - fout << " $INPUTFILE\"\n" + " $INPUTFILE\"\n" " progress = \"Processing Custom Rule\"\n" " promoteToFirstPass = true\n" " outputType = \"None\"\n" @@ -327,13 +330,13 @@ void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout, this->WriteHighLevelDirectives(root, fout); GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout); - fout << "# Top Level Project File" << std::endl; + fout << "# Top Level Project File\n"; // Specify BSP option if supplied by user const char* bspName = this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME"); if (!cmIsOff(bspName)) { - fout << " -bsp " << bspName << std::endl; + fout << " -bsp " << bspName << '\n'; } // Specify OS DIR if supplied by user @@ -348,14 +351,14 @@ void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout, } else { fout << osDirOption; } - fout << "\"" << this->OsDir << "\"" << std::endl; + fout << "\"" << this->OsDir << "\"\n"; } } void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout, std::string& all_target) { - fout << "CMakeFiles/" << all_target << " [Project]" << std::endl; + fout << "CMakeFiles/" << all_target << " [Project]\n"; // All known targets for (cmGeneratorTarget const* target : this->ProjectTargets) { if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY || @@ -366,7 +369,7 @@ void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout, continue; } fout << "CMakeFiles/" << target->GetName() + ".tgt" + FILE_EXTENSION - << " [Project]" << std::endl; + << " [Project]\n"; } } @@ -374,8 +377,8 @@ void cmGlobalGhsMultiGenerator::WriteProjectLine( std::ostream& fout, cmGeneratorTarget const* target, cmLocalGenerator* root, std::string& rootBinaryDir) { - const char* projName = target->GetProperty("GENERATOR_FILE_NAME"); - const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT"); + cmProp projName = target->GetProperty("GENERATOR_FILE_NAME"); + cmProp projType = target->GetProperty("GENERATOR_FILE_NAME_EXT"); if (projName && projType) { cmLocalGenerator* lg = target->GetLocalGenerator(); std::string dir = lg->GetCurrentBinaryDirectory(); @@ -388,9 +391,9 @@ void cmGlobalGhsMultiGenerator::WriteProjectLine( } } - std::string projFile = dir + projName + FILE_EXTENSION; + std::string projFile = dir + *projName + FILE_EXTENSION; fout << projFile; - fout << " " << projType << std::endl; + fout << ' ' << *projType << '\n'; } else { /* Should never happen */ std::string message = @@ -467,7 +470,8 @@ void cmGlobalGhsMultiGenerator::WriteAllTarget( if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - if (!cmIsOn(t->GetProperty("EXCLUDE_FROM_ALL"))) { + cmProp p = t->GetProperty("EXCLUDE_FROM_ALL"); + if (!(p && cmIsOn(*p))) { defaultTargets.push_back(t); } } @@ -583,14 +587,14 @@ cmGlobalGhsMultiGenerator::GenerateBuildCommand( /* if multiple top-projects are found in build directory * then prefer projectName top-project. */ - if (!cmContains(files, proj)) { + if (!cm::contains(files, proj)) { proj = files.at(0); } } makeCommand.Add("-top", proj); if (!targetNames.empty()) { - if (cmContains(targetNames, "clean")) { + if (cm::contains(targetNames, "clean")) { makeCommand.Add("-clean"); } else { for (const auto& tname : targetNames) { @@ -612,14 +616,14 @@ cmGlobalGhsMultiGenerator::GenerateBuildCommand( void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout, cmLocalGenerator* root) { - fout << "macro PROJ_NAME=" << root->GetProjectName() << std::endl; + fout << "macro PROJ_NAME=" << root->GetProjectName() << '\n'; char const* ghsGpjMacros = this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS"); if (nullptr != ghsGpjMacros) { std::vector<std::string> expandedList = cmExpandedList(std::string(ghsGpjMacros)); for (std::string const& arg : expandedList) { - fout << "macro " << arg << std::endl; + fout << "macro " << arg << '\n'; } } } @@ -642,30 +646,27 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives( tgt = cmStrCat((a ? a : ""), '_', (p ? p : ""), ".tgt"); } - fout << "primaryTarget=" << tgt << std::endl; - fout << "customization=" << root->GetBinaryDirectory() - << "/CMakeFiles/custom_rule.bod" << std::endl; - fout << "customization=" << root->GetBinaryDirectory() - << "/CMakeFiles/custom_target.bod" << std::endl; + /* clang-format off */ + fout << "primaryTarget=" << tgt << "\n" + "customization=" << root->GetBinaryDirectory() + << "/CMakeFiles/custom_rule.bod\n" + "customization=" << root->GetBinaryDirectory() + << "/CMakeFiles/custom_target.bod" << '\n'; + /* clang-format on */ 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) << '\n'; 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 b82e9f57b..12ca8b648 100644 --- a/Source/cmGlobalGhsMultiGenerator.h +++ b/Source/cmGlobalGhsMultiGenerator.h @@ -111,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/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index b6c343c1f..843b0f44d 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -12,13 +12,12 @@ #include <cmext/algorithm> #include <cmext/memory> -#include "cmsys/FStream.hxx" +#include <cm3p/json/reader.h> +#include <cm3p/json/value.h> +#include <cm3p/json/writer.h> -#include "cm_jsoncpp_reader.h" -#include "cm_jsoncpp_value.h" -#include "cm_jsoncpp_writer.h" +#include "cmsys/FStream.hxx" -#include "cmAlgorithms.h" #include "cmDocumentationEntry.h" #include "cmFortranParser.h" #include "cmGeneratedFileStream.h" @@ -46,7 +45,8 @@ #include "cmake.h" 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 ."; @@ -147,15 +147,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; } @@ -166,7 +166,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); } @@ -175,14 +175,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; @@ -191,14 +190,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)); } } @@ -206,11 +205,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. @@ -309,7 +308,7 @@ 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); @@ -334,23 +333,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; } @@ -392,9 +392,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; } @@ -435,8 +435,6 @@ cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm) #ifdef _WIN32 cm->GetState()->SetWindowsShell(true); #endif - // // Ninja is not ported to non-Unix OS yet. - // this->ForceUnixPaths = true; this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake"; } @@ -558,11 +556,11 @@ void cmGlobalNinjaGenerator::CleanMetaData() nullptr, cmSystemTools::OUTPUT_NONE)) { this->GetCMakeInstance()->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(); } }; @@ -626,10 +624,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; } @@ -686,10 +684,10 @@ void cmGlobalNinjaGenerator::CheckNinjaFeatures() bool cmGlobalNinjaGenerator::CheckLanguages( std::vector<std::string> const& languages, cmMakefile* mf) const { - if (cmContains(languages, "Fortran")) { + if (cm::contains(languages, "Fortran")) { return this->CheckFortran(mf); } - if (cmContains(languages, "Swift")) { + if (cm::contains(languages, "Swift")) { const std::string architectures = mf->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES"); if (architectures.find_first_of(';') != std::string::npos) { @@ -713,7 +711,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. Ninja 1.10 or higher is required." ; /* clang-format on */ @@ -991,7 +989,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")); @@ -1000,9 +999,9 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand( // Get a stream where to generate things. this->CompileCommandsStream = cm::make_unique<cmGeneratedFileStream>(buildFilePath); - *this->CompileCommandsStream << "["; + *this->CompileCommandsStream << "[\n"; } else { - *this->CompileCommandsStream << "," << std::endl; + *this->CompileCommandsStream << ",\n"; } std::string sourceFileName = sourceFile; @@ -1012,7 +1011,7 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand( } /* clang-format off */ - *this->CompileCommandsStream << "\n{\n" + *this->CompileCommandsStream << "{\n" << R"( "directory": ")" << cmGlobalGenerator::EscapeJSON(buildFileDir) << "\",\n" << R"( "command": ")" @@ -1095,8 +1094,8 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( case cmStateEnums::GLOBAL_TARGET: case cmStateEnums::UTILITY: { std::string path = - target->GetLocalGenerator()->GetCurrentBinaryDirectory() + - std::string("/") + target->GetName(); + cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/', + target->GetName()); std::string output = this->ConvertToNinjaPath(path); if (target->Target->IsPerConfig()) { output = this->BuildAlias(output, config); @@ -1120,8 +1119,8 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( for (BT<std::pair<std::string, bool>> const& util : target->GetUtilities()) { std::string d = - target->GetLocalGenerator()->GetCurrentBinaryDirectory() + "/" + - util.Value.first; + cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/', + util.Value.first); outputs.push_back(this->BuildAlias(this->ConvertToNinjaPath(d), config)); } } else { @@ -1348,12 +1347,13 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) // Setup target cmNinjaDeps configDeps; - build.Comment = "Folder: " + currentBinaryDir; + 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( - this->ConvertToNinjaPath(currentBinaryDir + "/all"), config); + build.Outputs.front() = this->BuildAlias(buildDirAllTarget, config); configDeps.emplace_back(build.Outputs.front()); for (DirectoryTarget::Target const& t : dt.Targets) { if (!t.ExcludeFromAll) { @@ -1363,7 +1363,7 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) for (DirectoryTarget::Dir const& d : dt.Children) { if (!d.ExcludeFromAll) { build.ExplicitDeps.emplace_back(this->BuildAlias( - this->ConvertToNinjaPath(d.Path + "/all"), config)); + this->ConvertToNinjaPath(cmStrCat(d.Path, "/all")), config)); } } // Write target @@ -1377,21 +1377,18 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) // Add shortcut target if (this->IsMultiConfig()) { for (auto const& config : configs) { - build.ExplicitDeps = { this->BuildAlias( - this->ConvertToNinjaPath(currentBinaryDir + "/all"), config) }; - build.Outputs.front() = - this->ConvertToNinjaPath(currentBinaryDir + "/all"); + 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( - this->ConvertToNinjaPath(currentBinaryDir + "/all"), config)); + build.ExplicitDeps.push_back( + this->BuildAlias(buildDirAllTarget, config)); } - build.Outputs.front() = - this->ConvertToNinjaPath(currentBinaryDir + "/all"); + build.Outputs.front() = buildDirAllTarget; this->WriteBuild(*this->GetDefaultFileStream(), build); } } @@ -1400,11 +1397,10 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) if (this->EnableCrossConfigBuild()) { build.ExplicitDeps.clear(); for (auto const& config : this->CrossConfigs) { - build.ExplicitDeps.push_back(this->BuildAlias( - this->ConvertToNinjaPath(currentBinaryDir + "/all"), config)); + build.ExplicitDeps.push_back( + this->BuildAlias(buildDirAllTarget, config)); } - build.Outputs.front() = this->BuildAlias( - this->ConvertToNinjaPath(currentBinaryDir + "/all"), "all"); + build.Outputs.front() = this->BuildAlias(buildDirAllTarget, "all"); this->WriteBuild(os, build); } } @@ -1616,7 +1612,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"; @@ -1807,7 +1804,7 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) // Write rule { cmNinjaRule rule("CLEAN"); - rule.Command = NinjaCmd() + " $FILE_ARG -t clean $TARGETS"; + 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); @@ -1921,7 +1918,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); @@ -1948,7 +1945,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( @@ -2076,7 +2073,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; } } @@ -2147,7 +2145,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; @@ -2193,7 +2192,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) { @@ -2296,7 +2296,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; } @@ -2332,8 +2332,8 @@ 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; @@ -2366,7 +2366,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; } } @@ -2402,7 +2403,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"]; @@ -2430,9 +2431,7 @@ void cmGlobalNinjaGenerator::AppendDirectoryForConfig( const std::string& suffix, std::string& dir) { if (!config.empty() && this->IsMultiConfig()) { - dir += prefix; - dir += config; - dir += suffix; + dir += cmStrCat(prefix, config, suffix); } } diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 90c9ef0d2..c31983ba5 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -20,6 +20,7 @@ #include "cmMakefile.h" #include "cmMakefileTargetGenerator.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateDirectory.h" #include "cmStateTypes.h" @@ -41,7 +42,6 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm) #else this->UseLinkScript = true; #endif - this->CommandDatabase = nullptr; this->IncludeDirective = "include"; this->DefineWindowsNULL = false; @@ -49,6 +49,8 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm) this->UnixCD = true; } +cmGlobalUnixMakefileGenerator3::~cmGlobalUnixMakefileGenerator3() = default; + void cmGlobalUnixMakefileGenerator3::EnableLanguage( std::vector<std::string> const& languages, cmMakefile* mf, bool optional) { @@ -116,6 +118,12 @@ void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory( gt->ObjectDirectory = dir; } +bool cmGlobalUnixMakefileGenerator3::CanEscapeOctothorpe() const +{ + // Make tools that use UNIX-style '/' paths also support '\' escaping. + return this->ForceUnixPaths; +} + void cmGlobalUnixMakefileGenerator3::Configure() { // Initialize CMAKE_EDIT_COMMAND cache entry. @@ -157,10 +165,9 @@ void cmGlobalUnixMakefileGenerator3::Generate() this->WriteMainMakefile2(); this->WriteMainCMakefile(); - if (this->CommandDatabase != nullptr) { - *this->CommandDatabase << std::endl << "]"; - delete this->CommandDatabase; - this->CommandDatabase = nullptr; + if (this->CommandDatabase) { + *this->CommandDatabase << "\n]"; + this->CommandDatabase.reset(); } } @@ -168,26 +175,26 @@ 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 << "[" << std::endl; + this->CommandDatabase = + cm::make_unique<cmGeneratedFileStream>(commandDatabaseName); + *this->CommandDatabase << "[\n"; } else { - *this->CommandDatabase << "," << std::endl; + *this->CommandDatabase << ",\n"; } - *this->CommandDatabase << "{" << std::endl + *this->CommandDatabase << "{\n" << R"( "directory": ")" << cmGlobalGenerator::EscapeJSON(workingDirectory) - << "\"," << std::endl + << "\",\n" << R"( "command": ")" << cmGlobalGenerator::EscapeJSON(compileCommand) - << "\"," << std::endl + << "\",\n" << R"( "file": ")" - << cmGlobalGenerator::EscapeJSON(sourceFile) << "\"" - << std::endl - << "}"; + << cmGlobalGenerator::EscapeJSON(sourceFile) + << "\"\n}"; } void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() @@ -343,19 +350,18 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() 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()) { + 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 (const auto& localGen : this->LocalGenerators) { + for (std::string const& outfile : + localGen->GetMakefile()->GetOutputFiles()) { cmakefileStream << " \"" << lg.MaybeConvertToRelativePath(binDir, outfile) << "\"\n"; } - } - - // add in all the directory information files - std::string tmpStr; - for (const auto& localGen : this->LocalGenerators) { tmpStr = cmStrCat(localGen->GetCurrentBinaryDirectory(), "/CMakeFiles/CMakeDirectoryInformation.cmake"); cmakefileStream << " \"" @@ -481,6 +487,78 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2( } } +namespace { +std::string ConvertToMakefilePathForUnix(std::string const& path) +{ + std::string result; + result.reserve(path.size()); + for (char c : path) { + switch (c) { + case '=': + // We provide 'EQUALS = =' to encode '=' in a non-assignment case. + result.append("$(EQUALS)"); + break; + case '$': + result.append("$$"); + break; + case '\\': + case ' ': + case '#': + result.push_back('\\'); + CM_FALLTHROUGH; + default: + result.push_back(c); + break; + } + } + return result; +} + +#if defined(_WIN32) && !defined(__CYGWIN__) +std::string ConvertToMakefilePathForWindows(std::string const& path) +{ + bool const quote = path.find_first_of(" #") != std::string::npos; + std::string result; + result.reserve(path.size() + (quote ? 2 : 0)); + if (quote) { + result.push_back('"'); + } + for (char c : path) { + switch (c) { + case '=': + // We provide 'EQUALS = =' to encode '=' in a non-assignment case. + result.append("$(EQUALS)"); + break; + case '$': + result.append("$$"); + break; + case '/': + result.push_back('\\'); + break; + default: + result.push_back(c); + break; + } + } + if (quote) { + result.push_back('"'); + } + return result; +} +#endif +} + +std::string cmGlobalUnixMakefileGenerator3::ConvertToMakefilePath( + std::string const& path) const +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + if (!this->ForceUnixPaths) { + return ConvertToMakefilePathForWindows(path); + } +#endif + return ConvertToMakefilePathForUnix(path); +} + std::vector<cmGlobalGenerator::GeneratedMakeCommand> cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( const std::string& makeProgram, const std::string& /*projectName*/, @@ -674,10 +752,10 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( } bool targetMessages = true; - if (const char* tgtMsg = + if (cmProp tgtMsg = this->GetCMakeInstance()->GetState()->GetGlobalProperty( "TARGET_MESSAGES")) { - targetMessages = cmIsOn(tgtMsg); + targetMessages = cmIsOn(*tgtMsg); } if (targetMessages) { @@ -697,9 +775,8 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # in target - progCmd << lg.ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progress.Dir), - cmOutputConverter::SHELL); + progCmd << lg.ConvertToOutputFormat(progress.Dir, + cmOutputConverter::SHELL); // std::set<cmGeneratorTarget const*> emitted; progCmd << " " @@ -711,9 +788,8 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << lg.ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progress.Dir), - cmOutputConverter::SHELL); + progCmd << lg.ConvertToOutputFormat(progress.Dir, + cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index 340a7efa5..1caa4b736 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -68,6 +68,13 @@ public: 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 { @@ -129,6 +136,12 @@ public: or dependencies. */ std::string GetEmptyRuleHackDepends() { return this->EmptyRuleHackDepends; } + /** + * Convert a file path to a Makefile target or dependency with + * escaping and quoting suitable for the generator's make tool. + */ + std::string ConvertToMakefilePath(std::string const& path) const; + // change the build command for speed std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, @@ -150,6 +163,9 @@ public: /** Does the make tool tolerate .DELETE_ON_ERROR? */ virtual bool AllowDeleteOnError() const { return true; } + /** Does the make tool interpret '\#' as '#'? */ + virtual bool CanEscapeOctothorpe() const; + bool IsIPOSupported() const override { return true; } void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override; @@ -232,7 +248,7 @@ protected: std::set<cmGeneratorTarget const*>& emitted); 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 ccb6c50f1..5dac072c2 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -6,12 +6,12 @@ #include <cm/memory> +#include <cm3p/json/reader.h> + #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" -#include "cm_jsoncpp_reader.h" - #include "cmAlgorithms.h" #include "cmDocumentationEntry.h" #include "cmGeneratorTarget.h" @@ -19,6 +19,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmSourceFile.h" +#include "cmStringAlgorithms.h" #include "cmVersion.h" #include "cmVisualStudioSlnData.h" #include "cmVisualStudioSlnParser.h" @@ -313,7 +314,7 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( version.clear(); } - if (version.find(this->GetPlatformToolsetString()) != 0) { + if (!cmHasPrefix(version, this->GetPlatformToolsetString())) { std::ostringstream e; /* clang-format off */ e << diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index f659ff3e3..b8c18b4ac 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -121,6 +121,8 @@ public: bool IsIPOSupported() const override { return true; } + virtual bool IsStdOutEncodingSupported() const { return false; } + static std::string GetInstalledNsightTegraVersion(); /** Return the first two components of CMAKE_SYSTEM_VERSION. */ diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index d0aec6193..7ada32511 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -91,7 +91,7 @@ void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout, cmGeneratorTarget const* t) { // check to see if this is a fortran build - const char* ext = ".vcproj"; + std::string ext = ".vcproj"; const char* project = "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \""; if (this->TargetIsFortranOnly(t)) { @@ -102,9 +102,9 @@ void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout, ext = ".csproj"; project = "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \""; } - const char* targetExt = t->GetProperty("GENERATOR_FILE_NAME_EXT"); + cmProp targetExt = t->GetProperty("GENERATOR_FILE_NAME_EXT"); if (targetExt) { - ext = targetExt; + ext = *targetExt; } std::string guid = this->GetGUID(dspname); @@ -198,9 +198,9 @@ void cmGlobalVisualStudio71Generator::WriteProjectConfigurations( std::vector<std::string> mapConfig; const char* dstConfig = i.c_str(); if (target.GetProperty("EXTERNAL_MSPROJECT")) { - if (const char* m = target.GetProperty("MAP_IMPORTED_CONFIG_" + - cmSystemTools::UpperCase(i))) { - cmExpandList(m, mapConfig); + if (cmProp m = target.GetProperty("MAP_IMPORTED_CONFIG_" + + cmSystemTools::UpperCase(i))) { + cmExpandList(*m, mapConfig); if (!mapConfig.empty()) { dstConfig = mapConfig[0].c_str(); } diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 97991240b..428c74863 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -128,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); } @@ -342,19 +342,19 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations( if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - const char* expath = target->GetProperty("EXTERNAL_MSPROJECT"); + cmProp expath = target->GetProperty("EXTERNAL_MSPROJECT"); if (expath) { std::set<std::string> allConfigurations(configs.begin(), configs.end()); - const char* mapping = target->GetProperty("VS_PLATFORM_MAPPING"); + cmProp mapping = target->GetProperty("VS_PLATFORM_MAPPING"); this->WriteProjectConfigurations(fout, target->GetName(), *target, configs, allConfigurations, - mapping ? mapping : ""); + mapping ? *mapping : ""); } else { const std::set<std::string>& configsPartOfDefaultBuild = this->IsPartOfDefaultBuild(configs, projectTargets, target); - const char* vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); + cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); if (vcprojName) { - this->WriteProjectConfigurations(fout, vcprojName, *target, configs, + this->WriteProjectConfigurations(fout, *vcprojName, *target, configs, configsPartOfDefaultBuild); } } @@ -375,17 +375,18 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( bool written = false; // handle external vc project files - const char* expath = target->GetProperty("EXTERNAL_MSPROJECT"); + cmProp expath = target->GetProperty("EXTERNAL_MSPROJECT"); if (expath) { std::string project = target->GetName(); - std::string location = expath; + std::string location = *expath; + cmProp p = target->GetProperty("VS_PROJECT_TYPE"); this->WriteExternalProject(fout, project, location, - target->GetProperty("VS_PROJECT_TYPE"), + p ? p->c_str() : nullptr, target->GetUtilities()); written = true; } else { - const char* vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); + cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); if (vcprojName) { cmLocalGenerator* lg = target->GetLocalGenerator(); std::string dir = lg->GetCurrentBinaryDirectory(); @@ -393,7 +394,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( if (dir == ".") { dir.clear(); // msbuild cannot handle ".\" prefix } - this->WriteProject(fout, vcprojName, dir, target); + this->WriteProject(fout, *vcprojName, dir, target); written = true; } } @@ -438,11 +439,11 @@ void cmGlobalVisualStudio7Generator::WriteTargetDepends( if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - const char* vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); + cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); if (vcprojName) { std::string dir = target->GetLocalGenerator()->GetCurrentSourceDirectory(); - this->WriteProjectDepends(fout, vcprojName, dir.c_str(), target); + this->WriteProjectDepends(fout, *vcprojName, dir, target); } } } @@ -505,13 +506,13 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections( const std::vector<std::string> propKeys = root->GetMakefile()->GetPropertyKeys(); for (std::string const& it : propKeys) { - if (it.find("VS_GLOBAL_SECTION_") == 0) { + if (cmHasLiteralPrefix(it, "VS_GLOBAL_SECTION_")) { std::string sectionType; std::string name = it.substr(18); - if (name.find("PRE_") == 0) { + if (cmHasLiteralPrefix(name, "PRE_")) { name = name.substr(4); sectionType = "preSolution"; - } else if (name.find("POST_") == 0) { + } else if (cmHasLiteralPrefix(name, "POST_")) { name = name.substr(5); sectionType = "postSolution"; } else @@ -526,8 +527,8 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections( extensibilityAddInsOverridden = true; } fout << "\tGlobalSection(" << name << ") = " << sectionType << "\n"; - std::vector<std::string> keyValuePairs = - cmExpandedList(root->GetMakefile()->GetProperty(it)); + cmProp p = root->GetMakefile()->GetProperty(it); + std::vector<std::string> keyValuePairs = cmExpandedList(p ? *p : ""); for (std::string const& itPair : keyValuePairs) { const std::string::size_type posEqual = itPair.find('='); if (posEqual != std::string::npos) { @@ -676,7 +677,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/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index 1c62fbd91..29ca1549c 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -142,6 +142,9 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() // Add a custom rule to re-run CMake if any input files changed. { + // The custom rule runs cmake so set UTF-8 pipes. + bool stdPipesUTF8 = true; + // Collect the input files used to generate all targets in this // project. std::vector<std::string> listFiles; @@ -160,7 +163,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() lg.AddCustomCommandToTarget( CMAKE_CHECK_BUILD_SYSTEM_TARGET, byproducts, no_depends, verifyCommandLines, cmCustomCommandType::PRE_BUILD, - "Checking File Globs", no_working_directory, false); + "Checking File Globs", no_working_directory, stdPipesUTF8); // Ensure ZERO_CHECK always runs in Visual Studio using MSBuild, // otherwise the prebuild command will not be run. @@ -192,7 +195,8 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() if (cmSourceFile* file = lg.AddCustomCommandToOutput( stamps, no_byproducts, listFiles, no_main_dependency, no_implicit_depends, commandLines, "Checking Build System", - no_working_directory, true, false)) { + no_working_directory, true, false, false, false, "", "", + stdPipesUTF8)) { gt->AddSource(file->ResolveFullPath()); } else { cmSystemTools::Error("Error adding rule for " + stamps[0]); @@ -240,9 +244,9 @@ void cmGlobalVisualStudio8Generator::WriteProjectConfigurations( std::vector<std::string> mapConfig; const char* dstConfig = i.c_str(); if (target.GetProperty("EXTERNAL_MSPROJECT")) { - if (const char* m = target.GetProperty("MAP_IMPORTED_CONFIG_" + - cmSystemTools::UpperCase(i))) { - cmExpandList(m, mapConfig); + if (cmProp m = target.GetProperty("MAP_IMPORTED_CONFIG_" + + cmSystemTools::UpperCase(i))) { + cmExpandList(*m, mapConfig); if (!mapConfig.empty()) { dstConfig = mapConfig[0].c_str(); } @@ -275,23 +279,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( - cmGeneratorExpression::Evaluate(prop, target.LocalGenerator, config)); + if (cmProp 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 (cmProp 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 diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h index 8f8e33b8e..6ce67d3e7 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; diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 29d3f1af1..c688da2a3 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -508,9 +508,9 @@ std::string cmGlobalVisualStudioGenerator::GetUtilityDepend( std::string cmGlobalVisualStudioGenerator::GetStartupProjectName( cmLocalGenerator const* root) const { - const char* n = root->GetMakefile()->GetProperty("VS_STARTUP_PROJECT"); - if (n && *n) { - std::string startup = n; + cmProp n = root->GetMakefile()->GetProperty("VS_STARTUP_PROJECT"); + if (n && !n->empty()) { + std::string startup = *n; if (this->FindTarget(startup)) { return startup; } else { @@ -809,9 +809,9 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly( // This allows the project to control the language choice in // a target with none of its own sources, e.g. when also using // object libraries. - const char* linkLang = gt->GetProperty("LINKER_LANGUAGE"); - if (linkLang && *linkLang) { - languages.insert(linkLang); + cmProp linkLang = gt->GetProperty("LINKER_LANGUAGE"); + if (linkLang && !linkLang->empty()) { + languages.insert(*linkLang); } // Intel Fortran .vfproj files do support the resource compiler. @@ -933,7 +933,7 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( { cmakeCommand, "-E", "__create_def", mdi->DefFile, objs_file }); cmCustomCommand command(outputs, empty, empty, commandLines, gt->Target->GetMakefile()->GetBacktrace(), - "Auto build dll exports", "."); + "Auto build dll exports", ".", true); commands.push_back(std::move(command)); } diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index 13ae32a55..605dc8b2a 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -366,6 +366,12 @@ bool cmGlobalVisualStudioVersionedGenerator::GetVSInstance( return vsSetupAPIHelper.GetVSInstanceInfo(dir); } +bool cmGlobalVisualStudioVersionedGenerator::GetVSInstanceVersion( + unsigned long long& vsInstanceVersion) const +{ + return vsSetupAPIHelper.GetVSInstanceVersion(vsInstanceVersion); +} + bool cmGlobalVisualStudioVersionedGenerator::IsDefaultToolset( const std::string& version) const { @@ -387,6 +393,21 @@ bool cmGlobalVisualStudioVersionedGenerator::IsDefaultToolset( return false; } +bool cmGlobalVisualStudioVersionedGenerator::IsStdOutEncodingSupported() const +{ + // Supported from Visual Studio 16.7 Preview 3. + if (this->Version > cmGlobalVisualStudioGenerator::VSVersion::VS16) { + return true; + } + if (this->Version < cmGlobalVisualStudioGenerator::VSVersion::VS16) { + return false; + } + unsigned long long const vsInstanceVersion16_7_P2 = 4503631666610212; + unsigned long long vsInstanceVersion; + return (this->GetVSInstanceVersion(vsInstanceVersion) && + vsInstanceVersion > vsInstanceVersion16_7_P2); +} + std::string cmGlobalVisualStudioVersionedGenerator::GetAuxiliaryToolset() const { const char* version = this->GetPlatformToolsetVersion(); diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h index abb609536..cbd3ba77c 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.h +++ b/Source/cmGlobalVisualStudioVersionedGenerator.h @@ -29,9 +29,13 @@ public: bool GetVSInstance(std::string& dir) const; + bool GetVSInstanceVersion(unsigned long long& vsInstanceVersion) const; + bool IsDefaultToolset(const std::string& version) const override; std::string GetAuxiliaryToolset() const override; + bool IsStdOutEncodingSupported() const override; + protected: cmGlobalVisualStudioVersionedGenerator( VSVersion version, cmake* cm, const std::string& name, diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx index 308ddda73..d6a7afa7a 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.cxx +++ b/Source/cmGlobalWatcomWMakeGenerator.cxx @@ -19,7 +19,7 @@ cmGlobalWatcomWMakeGenerator::cmGlobalWatcomWMakeGenerator(cmake* cm) #endif this->ToolSupportsColor = true; this->NeedSymbolicMark = true; - this->EmptyRuleHackCommand = "@cd ."; + this->EmptyRuleHackCommand = "@%null"; #ifdef _WIN32 cm->GetState()->SetWindowsShell(true); #endif @@ -44,6 +44,16 @@ void cmGlobalWatcomWMakeGenerator::EnableLanguage( this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional); } +bool cmGlobalWatcomWMakeGenerator::SetSystemName(std::string const& s, + cmMakefile* mf) +{ + if (mf->GetSafeDefinition("CMAKE_SYSTEM_PROCESSOR") == "I86") { + mf->AddDefinition("CMAKE_GENERATOR_CC", "wcl"); + mf->AddDefinition("CMAKE_GENERATOR_CXX", "wcl"); + } + return this->cmGlobalUnixMakefileGenerator3::SetSystemName(s, mf); +} + void cmGlobalWatcomWMakeGenerator::GetDocumentation( cmDocumentationEntry& entry) { diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h index c0daf8a7f..c47127feb 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.h +++ b/Source/cmGlobalWatcomWMakeGenerator.h @@ -41,6 +41,9 @@ public: /** Get the documentation entry for this generator. */ static void GetDocumentation(cmDocumentationEntry& entry); + /** Tell the generator about the target system. */ + bool SetSystemName(std::string const& s, cmMakefile* mf) override; + /** * Try to determine system information such as shared library * extension, pthreads, byte order etc. diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index e0005a4ed..a5ce5d18f 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -8,13 +8,13 @@ #include <cstring> #include <iomanip> #include <sstream> +#include <utility> #include <cm/memory> #include <cmext/algorithm> #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" @@ -33,6 +33,7 @@ #include "cmSourceGroup.h" #include "cmState.h" #include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" #include "cmXCode21Object.h" @@ -361,7 +362,7 @@ cmGlobalXCodeGenerator::GenerateBuildCommand( std::string projectArg = cmStrCat(projectName, ".xcodeproj"); makeCommand.Add(projectArg); } - if (cmContains(targetNames, "clean")) { + if (cm::contains(targetNames, "clean")) { makeCommand.Add("clean"); makeCommand.Add("-target", "ALL_BUILD"); } else { @@ -642,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(); } @@ -656,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(); @@ -668,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(); @@ -683,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) @@ -768,11 +769,15 @@ public: XCodeGeneratorExpressionInterpreter& operator=( XCodeGeneratorExpressionInterpreter const&) = delete; - using cmGeneratorExpressionInterpreter::Evaluate; - const std::string& Evaluate(const char* expression, const std::string& property) { + return this->Evaluate(std::string(expression ? expression : ""), property); + } + + const std::string& Evaluate(const std::string& expression, + const std::string& property) + { const std::string& processed = this->cmGeneratorExpressionInterpreter::Evaluate(expression, property); if (this->CompiledGeneratorExpression->GetHadContextSensitiveCondition()) { @@ -803,7 +808,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( // Add flags from target and source file properties. std::string flags; - const char* srcfmt = sf->GetProperty("Fortran_FORMAT"); + std::string const& srcfmt = sf->GetSafeProperty("Fortran_FORMAT"); switch (cmOutputConverter::GetFortranFormat(srcfmt)) { case cmOutputConverter::FortranFormatFixed: flags = "-fixed " + flags; @@ -815,22 +820,22 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( break; } const std::string COMPILE_FLAGS("COMPILE_FLAGS"); - if (const char* cflags = sf->GetProperty(COMPILE_FLAGS)) { - lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS)); + if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) { + lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS)); } const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); - if (const char* coptions = sf->GetProperty(COMPILE_OPTIONS)) { + if (cmProp coptions = sf->GetProperty(COMPILE_OPTIONS)) { lg->AppendCompileOptions( - flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); + flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS)); } // Add per-source definitions. BuildObjectListOrString flagsBuild(this, false); const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); - if (const char* compile_defs = sf->GetProperty(COMPILE_DEFINITIONS)) { + if (cmProp compile_defs = sf->GetProperty(COMPILE_DEFINITIONS)) { this->AppendDefines( flagsBuild, - genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS).c_str(), + genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS).c_str(), true); } @@ -848,9 +853,9 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( // Add per-source include directories. std::vector<std::string> includes; const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); - if (const char* cincludes = sf->GetProperty(INCLUDE_DIRECTORIES)) { + if (cmProp cincludes = sf->GetProperty(INCLUDE_DIRECTORIES)) { lg->AppendIncludeDirectories( - includes, genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES), + includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES), *sf); } lg->AppendFlags(flags, lg->GetIncludeFlags(includes, gtgt, lang, true)); @@ -879,10 +884,10 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( } // Add user-specified file attributes. - const char* extraFileAttributes = sf->GetProperty("XCODE_FILE_ATTRIBUTES"); + cmProp extraFileAttributes = sf->GetProperty("XCODE_FILE_ATTRIBUTES"); if (extraFileAttributes) { // Expand the list of attributes. - std::vector<std::string> attributes = cmExpandedList(extraFileAttributes); + std::vector<std::string> attributes = cmExpandedList(*extraFileAttributes); // Store the attributes. for (const auto& attribute : attributes) { @@ -904,7 +909,7 @@ void cmGlobalXCodeGenerator::AddXCodeProjBuildRule( "/CMakeLists.txt"); cmSourceFile* srcCMakeLists = target->Makefile->GetOrCreateSource( listfile, false, cmSourceFileLocationKind::Known); - if (!cmContains(sources, srcCMakeLists)) { + if (!cm::contains(sources, srcCMakeLists)) { sources.push_back(srcCMakeLists); } } @@ -993,11 +998,11 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( bool useLastKnownFileType = false; std::string fileType; if (sf) { - if (const char* e = sf->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) { - fileType = e; - } else if (const char* l = sf->GetProperty("XCODE_LAST_KNOWN_FILE_TYPE")) { + if (cmProp e = sf->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) { + fileType = *e; + } else if (cmProp l = sf->GetProperty("XCODE_LAST_KNOWN_FILE_TYPE")) { useLastKnownFileType = true; - fileType = l; + fileType = *l; } } if (fileType.empty()) { @@ -1420,8 +1425,8 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmGeneratorTarget* gtgt) bool cmGlobalXCodeGenerator::IsHeaderFile(cmSourceFile* sf) { - return cmContains(this->CMakeInstance->GetHeaderExtensions(), - sf->GetExtension()); + return cm::contains(this->CMakeInstance->GetHeaderExtensions(), + sf->GetExtension()); } cmXCodeObject* cmGlobalXCodeGenerator::CreateBuildPhase( @@ -1462,6 +1467,7 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( cmStrCat("$<TARGET_SONAME_FILE:", gtgt->GetName(), '>'); std::string str_link_file = cmStrCat("$<TARGET_LINKER_FILE:", gtgt->GetName(), '>'); + bool stdPipesUTF8 = true; cmCustomCommandLines cmd = cmMakeSingleCommandLine( { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library", str_file, str_so_file, str_link_file }); @@ -1469,7 +1475,7 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( cmCustomCommand command( std::vector<std::string>(), std::vector<std::string>(), std::vector<std::string>(), cmd, this->CurrentMakefile->GetBacktrace(), - "Creating symlinks", ""); + "Creating symlinks", "", stdPipesUTF8); postbuild.push_back(std::move(command)); } @@ -1859,18 +1865,18 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY || gtgt->GetType() == cmStateEnums::STATIC_LIBRARY) { this->CurrentLocalGenerator->GetStaticLibraryFlags( - extraLinkOptions, cmSystemTools::UpperCase(configName), llang, gtgt); + extraLinkOptions, configName, llang, gtgt); } else { - const char* targetLinkFlags = gtgt->GetProperty("LINK_FLAGS"); + cmProp targetLinkFlags = gtgt->GetProperty("LINK_FLAGS"); if (targetLinkFlags) { this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, - targetLinkFlags); + *targetLinkFlags); } if (!configName.empty()) { std::string linkFlagsVar = cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(configName)); - if (const char* linkFlags = gtgt->GetProperty(linkFlagsVar)) { - this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, linkFlags); + if (cmProp linkFlags = gtgt->GetProperty(linkFlagsVar)) { + this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, *linkFlags); } } std::vector<std::string> opts; @@ -1906,8 +1912,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, std::string pnsuffix; gtgt->GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName); - const char* version = gtgt->GetProperty("VERSION"); - const char* soversion = gtgt->GetProperty("SOVERSION"); + cmProp version = gtgt->GetProperty("VERSION"); + cmProp soversion = gtgt->GetProperty("SOVERSION"); if (!gtgt->HasSOName(configName) || gtgt->IsFrameworkOnApple()) { version = nullptr; soversion = nullptr; @@ -1923,9 +1929,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, std::string soName = pnbase; if (version && soversion) { realName += "."; - realName += version; + realName += *version; soName += "."; - soName += soversion; + soName += *soversion; } // Set attributes to specify the proper name for the target. @@ -1971,10 +1977,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, std::string fw_version = gtgt->GetFrameworkVersion(); buildSettings->AddAttribute("FRAMEWORK_VERSION", this->CreateString(fw_version)); - const char* ext = gtgt->GetProperty("BUNDLE_EXTENSION"); + cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION"); if (ext) { buildSettings->AddAttribute("WRAPPER_EXTENSION", - this->CreateString(ext)); + this->CreateString(*ext)); } std::string plist = this->ComputeInfoPListLocation(gtgt); @@ -2012,10 +2018,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, extraLinkOptions += " "; extraLinkOptions += createFlags; } - const char* ext = gtgt->GetProperty("BUNDLE_EXTENSION"); + cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION"); if (ext) { buildSettings->AddAttribute("WRAPPER_EXTENSION", - this->CreateString(ext)); + this->CreateString(*ext)); } std::string plist = this->ComputeInfoPListLocation(gtgt); // Xcode will create the final version of Info.plist at build time, @@ -2046,10 +2052,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, std::string fw_version = gtgt->GetFrameworkVersion(); buildSettings->AddAttribute("FRAMEWORK_VERSION", this->CreateString(fw_version)); - const char* ext = gtgt->GetProperty("BUNDLE_EXTENSION"); + cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION"); if (ext) { buildSettings->AddAttribute("WRAPPER_EXTENSION", - this->CreateString(ext)); + this->CreateString(*ext)); } std::string plist = this->ComputeInfoPListLocation(gtgt); @@ -2085,10 +2091,10 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, // Handle bundles and normal executables separately. if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) { - const char* ext = gtgt->GetProperty("BUNDLE_EXTENSION"); + cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION"); if (ext) { buildSettings->AddAttribute("WRAPPER_EXTENSION", - this->CreateString(ext)); + this->CreateString(*ext)); } std::string plist = this->ComputeInfoPListLocation(gtgt); // Xcode will create the final version of Info.plist at build time, @@ -2283,7 +2289,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, // Add Fortran source format attribute if property is set. const char* format = nullptr; - const char* tgtfmt = gtgt->GetProperty("Fortran_FORMAT"); + std::string const& tgtfmt = gtgt->GetSafeProperty("Fortran_FORMAT"); switch (cmOutputConverter::GetFortranFormat(tgtfmt)) { case cmOutputConverter::FortranFormatFixed: format = "fixed"; @@ -2406,12 +2412,13 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, // Convert "XCODE_ATTRIBUTE_*" properties directly. { for (auto const& prop : gtgt->GetPropertyKeys()) { - if (prop.find("XCODE_ATTRIBUTE_") == 0) { + if (cmHasLiteralPrefix(prop, "XCODE_ATTRIBUTE_")) { std::string attribute = prop.substr(16); this->FilterConfigurationAttribute(configName, attribute); if (!attribute.empty()) { + std::string const& pr = gtgt->GetSafeProperty(prop); std::string processed = cmGeneratorExpression::Evaluate( - gtgt->GetProperty(prop), this->CurrentLocalGenerator, configName); + pr, this->CurrentLocalGenerator, configName); buildSettings->AddAttribute(attribute, this->CreateString(processed)); } @@ -2530,8 +2537,8 @@ const char* cmGlobalXCodeGenerator::GetTargetLinkFlagsVar( const char* cmGlobalXCodeGenerator::GetTargetFileType( cmGeneratorTarget* target) { - if (const char* e = target->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) { - return e; + if (cmProp e = target->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) { + return e->c_str(); } switch (target->GetType()) { @@ -2563,8 +2570,8 @@ const char* cmGlobalXCodeGenerator::GetTargetFileType( const char* cmGlobalXCodeGenerator::GetTargetProductType( cmGeneratorTarget* target) { - if (const char* e = target->GetProperty("XCODE_PRODUCT_TYPE")) { - return e; + if (cmProp e = target->GetProperty("XCODE_PRODUCT_TYPE")) { + return e->c_str(); } switch (target->GetType()) { @@ -3141,12 +3148,12 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( // Put this last so it can override existing settings // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly. for (const auto& var : this->CurrentMakefile->GetDefinitions()) { - if (var.find("CMAKE_XCODE_ATTRIBUTE_") == 0) { + if (cmHasLiteralPrefix(var, "CMAKE_XCODE_ATTRIBUTE_")) { std::string attribute = var.substr(22); 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)); @@ -3197,10 +3204,9 @@ std::string cmGlobalXCodeGenerator::GetObjectsDirectory( void cmGlobalXCodeGenerator::ComputeArchitectures(cmMakefile* mf) { this->Architectures.clear(); - const char* osxArch = mf->GetDefinition("CMAKE_OSX_ARCHITECTURES"); const char* sysroot = mf->GetDefinition("CMAKE_OSX_SYSROOT"); - if (osxArch && sysroot) { - cmExpandList(std::string(osxArch), this->Architectures); + if (sysroot) { + mf->GetDefExpandList("CMAKE_OSX_ARCHITECTURES", this->Architectures); } if (this->Architectures.empty()) { @@ -3390,7 +3396,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; @@ -3400,12 +3406,12 @@ bool cmGlobalXCodeGenerator::OutputXCodeSharedSchemes( continue; } - const char* testee = obj->GetTarget()->GetProperty("XCTEST_TESTEE"); + cmProp testee = obj->GetTarget()->GetProperty("XCTEST_TESTEE"); if (!testee) { continue; } - testables[testee].push_back(obj); + testables[*testee].push_back(obj.get()); } // generate scheme @@ -3414,14 +3420,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(root, obj, testables[targetName], + cmXCodeScheme schm(root, obj.get(), testables[targetName], this->CurrentConfigurationTypes, this->XcodeVersion); schm.WriteXCodeSharedScheme(xcProjDir, @@ -3547,7 +3553,7 @@ std::string cmGlobalXCodeGenerator::RelativeToBinary(const std::string& p) std::string cmGlobalXCodeGenerator::XCodeEscapePath(const std::string& p) { - if (p.find(' ') != std::string::npos) { + if (p.find_first_of(" []") != std::string::npos) { std::string t = cmStrCat('"', p, '"'); return t; } @@ -3693,15 +3699,14 @@ bool cmGlobalXCodeGenerator::HasKnownObjectFileLocation( bool cmGlobalXCodeGenerator::UseEffectivePlatformName(cmMakefile* mf) const { - const char* epnValue = - this->GetCMakeInstance()->GetState()->GetGlobalProperty( - "XCODE_EMIT_EFFECTIVE_PLATFORM_NAME"); + cmProp epnValue = this->GetCMakeInstance()->GetState()->GetGlobalProperty( + "XCODE_EMIT_EFFECTIVE_PLATFORM_NAME"); if (!epnValue) { return mf->PlatformIsAppleEmbedded(); } - return cmIsOn(epnValue); + return cmIsOn(*epnValue); } bool cmGlobalXCodeGenerator::ShouldStripResourcePath(cmMakefile*) const diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index df68f803e..e380f1c0f 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -37,6 +37,10 @@ public: unsigned int version_number); 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 { @@ -249,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: @@ -273,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/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx index e03b2ca6c..0fcda4e3e 100644 --- a/Source/cmGraphVizWriter.cxx +++ b/Source/cmGraphVizWriter.cxx @@ -67,36 +67,6 @@ const char* getShapeForTarget(const cmLinkItem& item) return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN; } } - -struct DependeesDir -{ - template <typename T> - static const cmLinkItem& src(const T& con) - { - return con.src; - } - - template <typename T> - static const cmLinkItem& dst(const T& con) - { - return con.dst; - } -}; - -struct DependersDir -{ - template <typename T> - static const cmLinkItem& src(const T& con) - { - return con.dst; - } - - template <typename T> - static const cmLinkItem& dst(const T& con) - { - return con.src; - } -}; } cmGraphVizWriter::cmGraphVizWriter(std::string const& fileName, @@ -203,16 +173,18 @@ void cmGraphVizWriter::VisitLink(cmLinkItem const& depender, return; } - // write global data directly this->WriteConnection(this->GlobalFileStream, depender, dependee, scopeType); if (this->GeneratePerTarget) { - PerTargetConnections[depender].emplace_back(depender, dependee, scopeType); + auto fileStream = PerTargetFileStreams[depender.AsStr()].get(); + this->WriteNode(*fileStream, dependee); + this->WriteConnection(*fileStream, depender, dependee, scopeType); } if (this->GenerateDependers) { - TargetDependersConnections[dependee].emplace_back(dependee, depender, - scopeType); + auto fileStream = TargetDependersFileStreams[dependee.AsStr()].get(); + this->WriteNode(*fileStream, depender); + this->WriteConnection(*fileStream, depender, dependee, scopeType); } } @@ -316,99 +288,23 @@ void cmGraphVizWriter::Write() } } - // write global data and collect all connection data for per target graphs for (auto const gt : sortedGeneratorTargets) { auto item = cmLinkItem(gt, false, gt->GetBacktrace()); this->VisitItem(item); } - - if (this->GeneratePerTarget) { - WritePerTargetConnections<DependeesDir>(PerTargetConnections, - PerTargetFileStreams); - } - - if (this->GenerateDependers) { - WritePerTargetConnections<DependersDir>(TargetDependersConnections, - TargetDependersFileStreams); - } -} - -void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap, - const cmLinkItem& rootItem, - Connections& extendedCons, - std::set<cmLinkItem>& visitedItems) -{ - // some "targets" are not in map, e.g. linker flags as -lm or - // targets without dependency. - // in both cases we are finished with traversing the graph - if (connectionMap.find(rootItem) == connectionMap.cend()) { - return; - } - - const Connections& origCons = connectionMap.at(rootItem); - - for (const Connection& con : origCons) { - extendedCons.emplace_back(con); - const cmLinkItem& dstItem = con.dst; - bool const visited = visitedItems.find(dstItem) != visitedItems.cend(); - if (!visited) { - visitedItems.insert(dstItem); - FindAllConnections(connectionMap, dstItem, extendedCons, visitedItems); - } - } -} - -void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap, - const cmLinkItem& rootItem, - Connections& extendedCons) -{ - std::set<cmLinkItem> visitedItems = { rootItem }; - FindAllConnections(connectionMap, rootItem, extendedCons, visitedItems); -} - -template <typename DirFunc> -void cmGraphVizWriter::WritePerTargetConnections( - const ConnectionsMap& connections, const FileStreamMap& streams) -{ - // the per target connections must be extended by indirect dependencies - ConnectionsMap extendedConnections; - for (auto const& conPerTarget : connections) { - const cmLinkItem& rootItem = conPerTarget.first; - Connections& extendedCons = extendedConnections[conPerTarget.first]; - FindAllConnections(connections, rootItem, extendedCons); - } - - for (auto const& conPerTarget : extendedConnections) { - const cmLinkItem& rootItem = conPerTarget.first; - - // some of the nodes are excluded completely and are not written - if (this->ItemExcluded(rootItem)) { - continue; - } - - const Connections& cons = conPerTarget.second; - auto fileStream = streams.at(rootItem.AsStr()).get(); - - for (const Connection& con : cons) { - const cmLinkItem& src = DirFunc::src(con); - const cmLinkItem& dst = DirFunc::dst(con); - this->WriteNode(*fileStream, con.dst); - this->WriteConnection(*fileStream, src, dst, con.scopeType); - } - } } void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& fs, const std::string& name) { auto const escapedGraphName = EscapeForDotFile(name); - fs << "digraph \"" << escapedGraphName << "\" {" << std::endl; - fs << this->GraphHeader << std::endl; + fs << "digraph \"" << escapedGraphName << "\" {\n" + << this->GraphHeader << '\n'; } void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& fs) { - fs << "}" << std::endl; + fs << "}\n"; } void cmGraphVizWriter::WriteLegend(cmGeneratedFileStream& fs) @@ -416,52 +312,46 @@ void cmGraphVizWriter::WriteLegend(cmGeneratedFileStream& fs) // 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; + /* clang-format off */ + fs << "subgraph clusterLegend {\n" + " label = \"Legend\";\n" + // Set the color of the box surrounding the legend. + " color = black;\n" + // We use invisible edges just to enforce the layout. + " edge [ style = invis ];\n" + // Nodes. + " legendNode0 [ label = \"Executable\", shape = " + << GRAPHVIZ_NODE_SHAPE_EXECUTABLE << " ];\n" + " legendNode1 [ label = \"Static Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC << " ];\n" + " legendNode2 [ label = \"Shared Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED << " ];\n" + " legendNode3 [ label = \"Module Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE << " ];\n" + " legendNode4 [ label = \"Interface Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE << " ];\n" + " legendNode5 [ label = \"Object Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT << " ];\n" + " legendNode6 [ label = \"Unknown Library\", shape = " + << GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN << " ];\n" + " legendNode7 [ label = \"Custom Target\", shape = " + << GRAPHVIZ_NODE_SHAPE_UTILITY << " ];\n" + // Edges. + // Some of those are dummy (invisible) edges to enforce a layout. + " legendNode0 -> legendNode1 [ style = " + << GRAPHVIZ_EDGE_STYLE_PUBLIC << " ];\n" + " legendNode0 -> legendNode2 [ style = " + << GRAPHVIZ_EDGE_STYLE_PUBLIC << " ];\n" + " legendNode0 -> legendNode3;\n" + " legendNode1 -> legendNode4 [ label = \"Interface\", style = " + << GRAPHVIZ_EDGE_STYLE_INTERFACE << " ];\n" + " legendNode2 -> legendNode5 [ label = \"Private\", style = " + << GRAPHVIZ_EDGE_STYLE_PRIVATE << " ];\n" + " legendNode3 -> legendNode6 [ style = " + << GRAPHVIZ_EDGE_STYLE_PUBLIC << " ];\n" + " legendNode0 -> legendNode7;\n" + "}\n"; + /* clang-format off */ } void cmGraphVizWriter::WriteNode(cmGeneratedFileStream& fs, @@ -474,7 +364,7 @@ void cmGraphVizWriter::WriteNode(cmGeneratedFileStream& fs, auto const escapedLabel = EscapeForDotFile(itemNameWithAliases); fs << " \"" << nodeName << "\" [ label = \"" << escapedLabel - << "\", shape = " << getShapeForTarget(item) << " ];" << std::endl; + << "\", shape = " << getShapeForTarget(item) << " ];\n"; } void cmGraphVizWriter::WriteConnection(cmGeneratedFileStream& fs, @@ -486,11 +376,9 @@ void cmGraphVizWriter::WriteConnection(cmGeneratedFileStream& fs, auto const& dependeeName = dependee.AsStr(); fs << " \"" << this->NodeNames[dependerName] << "\" -> \"" - << this->NodeNames[dependeeName] << "\" "; - - fs << edgeStyle; - - fs << " // " << dependerName << " -> " << dependeeName << std::endl; + << this->NodeNames[dependeeName] << "\" " + << edgeStyle + << " // " << dependerName << " -> " << dependeeName << '\n'; } bool cmGraphVizWriter::ItemExcluded(cmLinkItem const& item) @@ -506,9 +394,9 @@ bool cmGraphVizWriter::ItemExcluded(cmLinkItem const& item) } if (item.Target->GetType() == cmStateEnums::UTILITY) { - if ((itemName.find("Nightly") == 0) || - (itemName.find("Continuous") == 0) || - (itemName.find("Experimental") == 0)) { + if (cmHasLiteralPrefix(itemName, "Nightly") || + cmHasLiteralPrefix(itemName, "Continuous") || + cmHasLiteralPrefix(itemName, "Experimental")) { return true; } } diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h index 9766068a2..578660dbb 100644 --- a/Source/cmGraphVizWriter.h +++ b/Source/cmGraphVizWriter.h @@ -7,18 +7,16 @@ #include <map> #include <memory> -#include <set> #include <string> -#include <utility> #include <vector> #include "cmsys/RegularExpression.hxx" #include "cmGeneratedFileStream.h" -#include "cmLinkItem.h" #include "cmLinkItemGraphVisitor.h" #include "cmStateTypes.h" +class cmLinkItem; class cmGlobalGenerator; /** This class implements writing files for graphviz (dot) for graphs @@ -49,22 +47,6 @@ private: using FileStreamMap = std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>; - struct Connection - { - Connection(cmLinkItem s, cmLinkItem d, std::string scope) - : src(std::move(s)) - , dst(std::move(d)) - , scopeType(std::move(scope)) - { - } - - cmLinkItem src; - cmLinkItem dst; - std::string scopeType; - }; - using Connections = std::vector<Connection>; - using ConnectionsMap = std::map<cmLinkItem, Connections>; - void VisitLink(cmLinkItem const& depender, cmLinkItem const& dependee, bool isDirectLink, std::string const& scopeType = ""); @@ -84,19 +66,6 @@ private: cmLinkItem const& dependeeTargetName, std::string const& edgeStyle); - void FindAllConnections(const ConnectionsMap& connectionMap, - const cmLinkItem& rootItem, - Connections& extendedCons, - std::set<cmLinkItem>& visitedItems); - - void FindAllConnections(const ConnectionsMap& connectionMap, - const cmLinkItem& rootItem, - Connections& extendedCons); - - template <typename DirFunc> - void WritePerTargetConnections(const ConnectionsMap& connections, - const FileStreamMap& streams); - bool ItemExcluded(cmLinkItem const& item); bool ItemNameFilteredOut(std::string const& itemName); bool TargetTypeEnabled(cmStateEnums::TargetType targetType) const; @@ -114,9 +83,6 @@ private: FileStreamMap PerTargetFileStreams; FileStreamMap TargetDependersFileStreams; - ConnectionsMap PerTargetConnections; - ConnectionsMap TargetDependersConnections; - std::string GraphName; std::string GraphHeader; std::string GraphNodePrefix; diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 290e064b4..5808f90eb 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -7,8 +7,7 @@ #include <cm/memory> #include <cm/string_view> - -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmConditionEvaluator.h" #include "cmExecutionStatus.h" diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx index 14264f487..ae801bb98 100644 --- a/Source/cmIncludeCommand.cxx +++ b/Source/cmIncludeCommand.cxx @@ -2,7 +2,9 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmIncludeCommand.h" +#include <map> #include <sstream> +#include <utility> #include "cmExecutionStatus.h" #include "cmGlobalGenerator.h" @@ -16,6 +18,11 @@ bool cmIncludeCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { + static std::map<std::string, cmPolicies::PolicyID> DeprecatedModules; + if (DeprecatedModules.empty()) { + DeprecatedModules["Documentation"] = cmPolicies::CMP0106; + } + if (args.empty() || args.size() > 4) { status.SetError("called with wrong number of arguments. " "include() only takes one file."); @@ -65,9 +72,35 @@ bool cmIncludeCommand(std::vector<std::string> const& args, } if (!cmSystemTools::FileIsFullPath(fname)) { + bool system = false; // Not a path. Maybe module. std::string module = cmStrCat(fname, ".cmake"); - std::string mfile = status.GetMakefile().GetModulesFile(module); + std::string mfile = status.GetMakefile().GetModulesFile(module, system); + + if (system) { + auto ModulePolicy = DeprecatedModules.find(fname); + if (ModulePolicy != DeprecatedModules.end()) { + cmPolicies::PolicyStatus PolicyStatus = + status.GetMakefile().GetPolicyStatus(ModulePolicy->second); + switch (PolicyStatus) { + case cmPolicies::WARN: { + status.GetMakefile().IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat(cmPolicies::GetPolicyWarning(ModulePolicy->second), + "\n")); + CM_FALLTHROUGH; + } + case cmPolicies::OLD: + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + mfile = ""; + break; + } + } + } + if (!mfile.empty()) { fname = mfile; } diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index d669ed7e9..178af738a 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -8,11 +8,10 @@ #include <utility> #include <cm/memory> +#include <cmext/string_view> #include "cmsys/Glob.hxx" -#include "cm_static_string_view.hxx" - #include "cmArgumentParser.h" #include "cmExecutionStatus.h" #include "cmExportSet.h" @@ -29,6 +28,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSubcommandTable.h" @@ -661,7 +661,6 @@ bool HandleTargetsMode(std::vector<std::string> const& args, // Nothing to do. An INTERFACE_LIBRARY can be installed, but the // only effect of that is to make it exportable. It installs no // other files itself. - break; default: // This should never happen due to the above type check. // Ignore the case. @@ -680,9 +679,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, } if (createInstallGeneratorsForTargetFileSets && !namelinkOnly) { - const char* files = target.GetProperty("PRIVATE_HEADER"); - if ((files) && (*files)) { - std::vector<std::string> relFiles = cmExpandedList(files); + cmProp files = target.GetProperty("PRIVATE_HEADER"); + if (files && !files->empty()) { + std::vector<std::string> relFiles = cmExpandedList(*files); std::vector<std::string> absFiles; if (!helper.MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) { return false; @@ -703,8 +702,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args, } files = target.GetProperty("PUBLIC_HEADER"); - if ((files) && (*files)) { - std::vector<std::string> relFiles = cmExpandedList(files); + if (files && !files->empty()) { + std::vector<std::string> relFiles = cmExpandedList(*files); std::vector<std::string> absFiles; if (!helper.MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) { return false; @@ -725,8 +724,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args, } files = target.GetProperty("RESOURCE"); - if ((files) && (*files)) { - std::vector<std::string> relFiles = cmExpandedList(files); + if (files && !files->empty()) { + std::vector<std::string> relFiles = cmExpandedList(*files); std::vector<std::string> absFiles; if (!helper.MakeFilesFullPath("RESOURCE", relFiles, absFiles)) { return false; diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx index 31ba63f2c..a034689c0 100644 --- a/Source/cmInstallCommandArguments.cxx +++ b/Source/cmInstallCommandArguments.cxx @@ -4,7 +4,7 @@ #include <utility> -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmRange.h" #include "cmSystemTools.h" diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 2c53a2824..6e3508c2d 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 @@ -33,18 +35,15 @@ cmInstallExportGenerator::cmInstallExportGenerator( { 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 cf28b35d8..43dd00da4 100644 --- a/Source/cmInstallExportGenerator.h +++ b/Source/cmInstallExportGenerator.h @@ -7,6 +7,7 @@ #include <cstddef> #include <iosfwd> +#include <memory> #include <string> #include <vector> @@ -30,8 +31,12 @@ public: 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; @@ -61,7 +66,7 @@ protected: std::string TempDir; std::string MainImportFile; - cmExportInstallFileGenerator* EFGen; + std::unique_ptr<cmExportInstallFileGenerator> EFGen; }; #endif diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index e05daa8d5..178d5df31 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -18,6 +18,7 @@ #include "cmMessageType.h" #include "cmOutputConverter.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -133,8 +134,10 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( cmMakefile const* mf = this->Target->Target->GetMakefile(); // Get App Bundle Extension - const char* ext = this->Target->GetProperty("BUNDLE_EXTENSION"); - if (!ext) { + std::string ext; + if (cmProp p = this->Target->GetProperty("BUNDLE_EXTENSION")) { + ext = *p; + } else { ext = "app"; } diff --git a/Source/cmInstalledFile.cxx b/Source/cmInstalledFile.cxx index a65ae037e..32395d10e 100644 --- a/Source/cmInstalledFile.cxx +++ b/Source/cmInstalledFile.cxx @@ -42,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); @@ -50,7 +51,8 @@ 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); diff --git a/Source/cmInstalledFile.h b/Source/cmInstalledFile.h index 698151e3c..07f70816e 100644 --- a/Source/cmInstalledFile.h +++ b/Source/cmInstalledFile.h @@ -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; diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx index dd3638654..9f17f1557 100644 --- a/Source/cmJsonObjects.cxx +++ b/Source/cmJsonObjects.cxx @@ -28,6 +28,7 @@ #include "cmLinkLineComputer.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmPropertyMap.h" #include "cmSourceFile.h" #include "cmState.h" @@ -90,7 +91,8 @@ void cmGetCMakeInputs(const cmGlobalGenerator* gg, const std::string startOfFile = lf.substr(0, cmakeRootDir.size()); const bool isInternal = (startOfFile == cmakeRootDir); - const bool isTemporary = !isInternal && (lf.find(buildDir + '/') == 0); + const bool isTemporary = + !isInternal && (cmHasPrefix(lf, buildDir + '/')); std::string toAdd = lf; if (!sourceDir.empty()) { @@ -274,14 +276,14 @@ static Json::Value DumpSourceFilesList( std::string compileFlags = ld.Flags; const std::string COMPILE_FLAGS("COMPILE_FLAGS"); - if (const char* cflags = file->GetProperty(COMPILE_FLAGS)) { + if (cmProp cflags = file->GetProperty(COMPILE_FLAGS)) { lg->AppendFlags(compileFlags, - genexInterpreter.Evaluate(cflags, COMPILE_FLAGS)); + genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS)); } const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); - if (const char* coptions = file->GetProperty(COMPILE_OPTIONS)) { + if (cmProp coptions = file->GetProperty(COMPILE_OPTIONS)) { lg->AppendCompileOptions( - compileFlags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); + compileFlags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS)); } fileData.Flags = compileFlags; @@ -289,9 +291,9 @@ static Json::Value DumpSourceFilesList( std::vector<std::string> includes; const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); - if (const char* cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) { + if (cmProp cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) { const std::string& evaluatedIncludes = - genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES); + genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES); lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file); for (const auto& include : includes) { @@ -308,17 +310,17 @@ static Json::Value DumpSourceFilesList( const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); std::set<std::string> defines; - if (const char* defs = file->GetProperty(COMPILE_DEFINITIONS)) { + if (cmProp defs = file->GetProperty(COMPILE_DEFINITIONS)) { lg->AppendDefines( - defines, genexInterpreter.Evaluate(defs, COMPILE_DEFINITIONS)); + defines, genexInterpreter.Evaluate(*defs, COMPILE_DEFINITIONS)); } const std::string defPropName = "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); - if (const char* config_defs = file->GetProperty(defPropName)) { + if (cmProp config_defs = file->GetProperty(defPropName)) { lg->AppendDefines( defines, - genexInterpreter.Evaluate(config_defs, COMPILE_DEFINITIONS)); + genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS)); } defines.insert(ld.Defines.begin(), ld.Defines.end()); diff --git a/Source/cmJsonObjects.h b/Source/cmJsonObjects.h index 64291cc06..2fd4b26f3 100644 --- a/Source/cmJsonObjects.h +++ b/Source/cmJsonObjects.h @@ -8,7 +8,7 @@ #include <string> #include <vector> -#include "cm_jsoncpp_value.h" +#include <cm3p/json/value.h> class cmake; class cmGlobalGenerator; diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h index 0ea25c0aa..3d9293528 100644 --- a/Source/cmLinkItem.h +++ b/Source/cmLinkItem.h @@ -10,7 +10,8 @@ #include <string> #include <vector> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmListFileCache.h" #include "cmSystemTools.h" #include "cmTargetLinkLibraryType.h" @@ -53,6 +54,9 @@ struct cmLinkImplementationLibraries // Libraries linked directly in other configurations. // Needed only for OLD behavior of CMP0003. std::vector<cmLinkItem> WrongConfigLibraries; + + // Whether the list depends on a genex referencing the configuration. + bool HadContextSensitiveCondition = false; }; struct cmLinkInterfaceLibraries @@ -62,6 +66,9 @@ struct cmLinkInterfaceLibraries // Whether the list depends on a genex referencing the head target. bool HadHeadSensitiveCondition = false; + + // Whether the list depends on a genex referencing the configuration. + bool HadContextSensitiveCondition = false; }; struct cmLinkInterface : public cmLinkInterfaceLibraries @@ -81,6 +88,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 @@ -100,6 +110,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. @@ -121,7 +134,7 @@ inline cmTargetLinkLibraryType CMP0003_ComputeLinkType( // Check if any entry in the list matches this configuration. std::string configUpper = cmSystemTools::UpperCase(config); - if (cmContains(debugConfigs, configUpper)) { + if (cm::contains(debugConfigs, configUpper)) { return DEBUG_LibraryType; } // The current configuration is not a debug configuration. diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx index 65ed34caa..c50a78684 100644 --- a/Source/cmLinkLineDeviceComputer.cxx +++ b/Source/cmLinkLineDeviceComputer.cxx @@ -6,7 +6,8 @@ #include <set> #include <utility> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmComputeLinkInformation.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" @@ -14,6 +15,7 @@ #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmStateDirectory.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" @@ -176,11 +178,11 @@ bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg, return false; } - if (const char* resolveDeviceSymbols = + if (cmProp resolveDeviceSymbols = target.GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) { // If CUDA_RESOLVE_DEVICE_SYMBOLS has been explicitly set we need // to honor the value no matter what it is. - return cmIsOn(resolveDeviceSymbols); + return cmIsOn(*resolveDeviceSymbols); } // Determine if we have any dependencies that require @@ -188,10 +190,10 @@ bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg, cmGeneratorTarget::LinkClosure const* closure = target.GetLinkClosure(config); - if (cmContains(closure->Languages, "CUDA")) { - if (const char* separableCompilation = + if (cm::contains(closure->Languages, "CUDA")) { + if (cmProp separableCompilation = target.GetProperty("CUDA_SEPARABLE_COMPILATION")) { - if (cmIsOn(separableCompilation)) { + if (cmIsOn(*separableCompilation)) { bool doDeviceLinking = false; switch (target.GetType()) { case cmStateEnums::SHARED_LIBRARY: diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx index 5200a160f..edec613ed 100644 --- a/Source/cmListCommand.cxx +++ b/Source/cmListCommand.cxx @@ -16,11 +16,11 @@ #include <vector> #include <cm/memory> +#include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/RegularExpression.hxx" -#include "cm_static_string_view.hxx" - #include "cmAlgorithms.h" #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" @@ -66,7 +66,7 @@ bool GetList(std::vector<std::string>& list, const std::string& var, // expand the variable into a list cmExpandList(listString, list, true); // if no empty elements then just return - if (!cmContains(list, std::string())) { + if (!cm::contains(list, std::string())) { return true; } // if we have empty elements we need to check policy CMP0007 @@ -1051,6 +1051,7 @@ public: UNINITIALIZED, STRING, FILE_BASENAME, + NATURAL, }; enum class CaseSensitivity { @@ -1074,10 +1075,25 @@ protected: : nullptr; } + using ComparisonFunction = + std::function<bool(const std::string&, const std::string&)>; + ComparisonFunction GetComparisonFunction(Compare compare) + { + if (compare == Compare::NATURAL) { + return std::function<bool(const std::string&, const std::string&)>( + [](const std::string& x, const std::string& y) { + return cmSystemTools::strverscmp(x, y) < 0; + }); + } + return std::function<bool(const std::string&, const std::string&)>( + [](const std::string& x, const std::string& y) { return x < y; }); + } + public: cmStringSorter(Compare compare, CaseSensitivity caseSensitivity, Order desc = Order::ASCENDING) : filters{ GetCompareFilter(compare), GetCaseFilter(caseSensitivity) } + , sortMethod(GetComparisonFunction(compare)) , descending(desc == Order::DESCENDING) { } @@ -1099,15 +1115,16 @@ public: std::string bf = ApplyFilter(b); bool result; if (descending) { - result = bf < af; + result = sortMethod(bf, af); } else { - result = af < bf; + result = sortMethod(af, bf); } return result; } protected: StringFilter filters[2] = { nullptr, nullptr }; + ComparisonFunction sortMethod; bool descending; }; @@ -1142,6 +1159,8 @@ bool HandleSortCommand(std::vector<std::string> const& args, sortCompare = cmStringSorter::Compare::STRING; } else if (argument == "FILE_BASENAME") { sortCompare = cmStringSorter::Compare::FILE_BASENAME; + } else if (argument == "NATURAL") { + sortCompare = cmStringSorter::Compare::NATURAL; } else { std::string error = cmStrCat(messageHint, "value \"", argument, "\" for option \"", diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 47679c932..7ebb02f49 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 9cae8277b..89902ff30 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/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx index 92258e27b..5790e169c 100644 --- a/Source/cmLoadCommandCommand.cxx +++ b/Source/cmLoadCommandCommand.cxx @@ -1,5 +1,15 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ + +#if !defined(_WIN32) && !defined(__sun) +// POSIX APIs are needed +# define _POSIX_C_SOURCE 200809L +#endif +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) +// For isascii +# define _XOPEN_SOURCE 700 +#endif + #include "cmLoadCommandCommand.h" #include <csignal> diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx index 025ef7e6b..278ec8b14 100644 --- a/Source/cmLocalCommonGenerator.cxx +++ b/Source/cmLocalCommonGenerator.cxx @@ -50,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/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index f592b7bd7..3b3f110dc 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -6,7 +6,6 @@ #include <cassert> #include <cstdio> #include <cstdlib> -#include <cstring> #include <initializer_list> #include <iterator> #include <sstream> @@ -20,7 +19,6 @@ #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" @@ -35,8 +33,8 @@ #include "cmInstallScriptGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmLinkLineComputer.h" -#include "cmLinkLineDeviceComputer.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" #include "cmSourceFileLocation.h" @@ -310,29 +308,35 @@ void cmLocalGenerator::GenerateTestFiles() cmGeneratedFileStream fout(file); fout.SetCopyIfDifferent(true); - fout << "# CMake generated Testfile for " << std::endl - << "# Source directory: " - << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl - << "# Build directory: " - << this->StateSnapshot.GetDirectory().GetCurrentBinary() << std::endl - << "# " << std::endl - << "# This file includes the relevant testing commands " - << "required for " << std::endl - << "# testing this directory and lists subdirectories to " - << "be tested as well." << std::endl; - - const char* testIncludeFile = - this->Makefile->GetProperty("TEST_INCLUDE_FILE"); + fout << "# CMake generated Testfile for \n" + "# Source directory: " + << this->StateSnapshot.GetDirectory().GetCurrentSource() + << "\n" + "# Build directory: " + << this->StateSnapshot.GetDirectory().GetCurrentBinary() + << "\n" + "# \n" + "# This file includes the relevant testing commands " + "required for \n" + "# testing this directory and lists subdirectories to " + "be tested as well.\n"; + + std::string resourceSpecFile = + this->Makefile->GetSafeDefinition("CTEST_RESOURCE_SPEC_FILE"); + if (!resourceSpecFile.empty()) { + fout << "set(CTEST_RESOURCE_SPEC_FILE \"" << resourceSpecFile << "\")\n"; + } + + cmProp testIncludeFile = this->Makefile->GetProperty("TEST_INCLUDE_FILE"); if (testIncludeFile) { - fout << "include(\"" << testIncludeFile << "\")" << std::endl; + fout << "include(\"" << *testIncludeFile << "\")\n"; } - const char* testIncludeFiles = - this->Makefile->GetProperty("TEST_INCLUDE_FILES"); + cmProp testIncludeFiles = this->Makefile->GetProperty("TEST_INCLUDE_FILES"); if (testIncludeFiles) { - std::vector<std::string> includesList = cmExpandedList(testIncludeFiles); + std::vector<std::string> includesList = cmExpandedList(*testIncludeFiles); for (std::string const& i : includesList) { - fout << "include(\"" << i << "\")" << std::endl; + fout << "include(\"" << i << "\")\n"; } } @@ -349,18 +353,18 @@ void cmLocalGenerator::GenerateTestFiles() std::string outP = i.GetDirectory().GetCurrentBinary(); outP = this->MaybeConvertToRelativePath(parentBinDir, outP); outP = cmOutputConverter::EscapeForCMake(outP); - fout << "subdirs(" << outP << ")" << std::endl; + fout << "subdirs(" << outP << ")\n"; } // Add directory labels property const char* directoryLabels = this->Makefile->GetDefinition("CMAKE_DIRECTORY_LABELS"); - const char* labels = this->Makefile->GetProperty("LABELS"); + cmProp labels = this->Makefile->GetProperty("LABELS"); if (labels || directoryLabels) { fout << "set_directory_properties(PROPERTIES LABELS "; if (labels) { - fout << cmOutputConverter::EscapeForCMake(labels); + fout << cmOutputConverter::EscapeForCMake(*labels); } if (labels && directoryLabels) { fout << ";"; @@ -368,7 +372,7 @@ void cmLocalGenerator::GenerateTestFiles() if (directoryLabels) { fout << cmOutputConverter::EscapeForCMake(directoryLabels); } - fout << ")" << std::endl; + fout << ")\n"; } } @@ -489,16 +493,17 @@ void cmLocalGenerator::GenerateInstallRules() fout.SetCopyIfDifferent(true); // Write the header. + /* clang-format off */ fout << "# Install script for directory: " - << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl - << std::endl; - fout << "# Set the install prefix" << std::endl - << "if(NOT DEFINED CMAKE_INSTALL_PREFIX)" << std::endl - << " set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")" << std::endl - << "endif()" << std::endl + << this->StateSnapshot.GetDirectory().GetCurrentSource() + << "\n\n" + "# Set the install prefix\n" + "if(NOT DEFINED CMAKE_INSTALL_PREFIX)\n" + " set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")\n" + "endif()\n" << R"(string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX )" - << "\"${CMAKE_INSTALL_PREFIX}\")" << std::endl - << std::endl; + << "\"${CMAKE_INSTALL_PREFIX}\")\n\n"; + /* clang-format on */ // Write support code for generating per-configuration install rules. /* clang-format off */ @@ -572,6 +577,71 @@ void cmLocalGenerator::GenerateInstallRules() /* clang-format on */ } + // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM so that + // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)` + // has same platform variable as when running cmake + if (const char* platform = this->Makefile->GetDefinition( + "CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM")) { + /* clang-format off */ + fout << + "# Set default install directory permissions.\n" + "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM)\n" + " set(CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM \"" + << platform << "\")\n" + "endif()\n" + "\n"; + /* clang-format on */ + } + + // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL so that + // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)` + // has same tool selected as when running cmake + if (const char* command = + this->Makefile->GetDefinition("CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL")) { + /* clang-format off */ + fout << + "# Set default install directory permissions.\n" + "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL)\n" + " set(CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL \"" + << command << "\")\n" + "endif()\n" + "\n"; + /* clang-format on */ + } + + // Write out CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND so that + // installed code that uses `file(GET_RUNTIME_DEPENDENCIES)` + // has same path to the tool as when running cmake + if (const char* command = this->Makefile->GetDefinition( + "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND")) { + /* clang-format off */ + fout << + "# Set default install directory permissions.\n" + "if(NOT DEFINED CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND)\n" + " set(CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND \"" + << command << "\")\n" + "endif()\n" + "\n"; + /* clang-format on */ + } + + // Write out CMAKE_OBJDUMP so that installed code that uses + // `file(GET_RUNTIME_DEPENDENCIES)` and hasn't specified + // CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND has consistent + // logic to fallback to CMAKE_OBJDUMP when `objdump` is + // not on the path + if (const char* command = this->Makefile->GetDefinition("CMAKE_OBJDUMP")) { + /* clang-format off */ + fout << + "# Set default install directory permissions.\n" + "if(NOT DEFINED CMAKE_OBJDUMP)\n" + " set(CMAKE_OBJDUMP \"" + << command << "\")\n" + "endif()\n" + "\n"; + /* clang-format on */ + } + // Ask each install generator to write its code. cmPolicies::PolicyStatus status = this->GetPolicyStatus(cmPolicies::CMP0082); auto const& installers = this->Makefile->GetInstallGenerators(); @@ -613,8 +683,7 @@ void cmLocalGenerator::GenerateInstallRules() if (!c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) { std::string odir = c.GetDirectory().GetCurrentBinary(); cmSystemTools::ConvertToUnixSlashes(odir); - fout << " include(\"" << odir << "/cmake_install.cmake\")" - << std::endl; + fout << " include(\"" << odir << "/cmake_install.cmake\")\n"; } } fout << "\n"; @@ -736,14 +805,14 @@ bool cmLocalGenerator::ComputeTargetCompileFeatures() if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { auto copyStandardToObjLang = [&](LanguagePair const& lang) -> bool { if (!target->GetProperty(cmStrCat(lang.first, "_STANDARD"))) { - auto* standard = + cmProp standard = target->GetProperty(cmStrCat(lang.second, "_STANDARD")); if (!standard) { - standard = this->Makefile->GetDefinition( + standard = this->Makefile->GetDef( cmStrCat("CMAKE_", lang.second, "_STANDARD_DEFAULT")); } target->Target->SetProperty(cmStrCat(lang.first, "_STANDARD"), - standard); + standard ? standard->c_str() : nullptr); return true; } return false; @@ -752,9 +821,9 @@ bool cmLocalGenerator::ComputeTargetCompileFeatures() const char* property) { if (!target->GetProperty(cmStrCat(lang.first, property)) && target->GetProperty(cmStrCat(lang.second, property))) { - target->Target->SetProperty( - cmStrCat(lang.first, property), - target->GetProperty(cmStrCat(lang.second, property))); + cmProp p = target->GetProperty(cmStrCat(lang.second, property)); + target->Target->SetProperty(cmStrCat(lang.first, property), + p ? p->c_str() : nullptr); } }; for (auto const& lang : pairedLanguages) { @@ -763,8 +832,8 @@ bool cmLocalGenerator::ComputeTargetCompileFeatures() copyPropertyToObjLang(lang, "_EXTENSIONS"); } } - if (const char* standard = target->GetProperty("CUDA_STANDARD")) { - if (std::string{ standard } == "98") { + if (cmProp standard = target->GetProperty("CUDA_STANDARD")) { + if (*standard == "98") { target->Target->SetProperty("CUDA_STANDARD", "03"); } } @@ -792,10 +861,13 @@ cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const const char* cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target, const std::string& prop) { + cmProp p; if (target) { - return target->GetProperty(prop); + p = target->GetProperty(prop); + } else { + p = this->Makefile->GetProperty(prop); } - return this->Makefile->GetProperty(prop); + return p ? p->c_str() : nullptr; } std::string cmLocalGenerator::ConvertToIncludeReference( @@ -899,7 +971,7 @@ std::string cmLocalGenerator::GetIncludeFlags( if ((sep[0] != ' ') && !flags.empty() && flags.back() == sep[0]) { flags.back() = ' '; } - return flags; + return cmTrimWhitespace(flags); } void cmLocalGenerator::AddCompileOptions(std::string& flags, @@ -922,9 +994,9 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, if (const char* langFlagRegexStr = this->Makefile->GetDefinition(langFlagRegexVar)) { // Filter flags acceptable to this language. - if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) { + if (cmProp targetFlags = target->GetProperty("COMPILE_FLAGS")) { std::vector<std::string> opts; - cmSystemTools::ParseWindowsCommandLine(targetFlags, opts); + cmSystemTools::ParseWindowsCommandLine(targetFlags->c_str(), opts); // Re-escape these flags since COMPILE_FLAGS were already parsed // as a command line above. std::string compileOpts; @@ -939,10 +1011,10 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, this->AppendCompileOptions(flags, targetCompileOpts, langFlagRegexStr); } else { // Use all flags. - if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) { + if (cmProp targetFlags = target->GetProperty("COMPILE_FLAGS")) { // COMPILE_FLAGS are not escaped for historical reasons. std::string compileFlags; - this->AppendFlags(compileFlags, targetFlags); + this->AppendFlags(compileFlags, *targetFlags); if (!compileFlags.empty()) { flags.emplace_back(std::move(compileFlags)); } @@ -954,11 +1026,11 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, } for (auto const& it : target->GetMaxLanguageStandards()) { - const char* standard = target->GetProperty(it.first + "_STANDARD"); + cmProp standard = target->GetProperty(it.first + "_STANDARD"); if (!standard) { continue; } - if (this->Makefile->IsLaterStandard(it.first, standard, it.second)) { + if (this->Makefile->IsLaterStandard(it.first, *standard, it.second)) { std::ostringstream e; e << "The COMPILE_FEATURES property of target \"" << target->GetName() << "\" was evaluated when computing the link " @@ -967,12 +1039,11 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, << "\" for that computation. Computing the " "COMPILE_FEATURES based on the link implementation resulted in a " "higher \"" - << it.first << "_STANDARD\" \"" << standard + << it.first << "_STANDARD\" \"" << *standard << "\". " "This is not permitted. The COMPILE_FEATURES may not both depend " "on " - "and be depended on by the link implementation." - << std::endl; + "and be depended on by the link implementation.\n"; this->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } @@ -995,10 +1066,10 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, cmGeneratorTarget::ManagedType::Managed) { // add /JMC flags if target property VS_JUST_MY_CODE_DEBUGGING is set // to ON - if (char const* jmcExprGen = + if (cmProp jmcExprGen = target->GetProperty("VS_JUST_MY_CODE_DEBUGGING")) { std::string isJMCEnabled = - cmGeneratorExpression::Evaluate(jmcExprGen, this, config); + cmGeneratorExpression::Evaluate(*jmcExprGen, this, config); if (cmIsOn(isJMCEnabled)) { std::vector<std::string> optVec = cmExpandedList(jmc); std::string jmcFlags; @@ -1018,7 +1089,8 @@ cmTarget* cmLocalGenerator::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, cmObjectLibraryCommands objLibCommands, + bool stdPipesUTF8) { cmTarget* t = this->Makefile->GetCustomCommandTarget( target, objLibCommands, this->DirectoryBacktrace); @@ -1029,7 +1101,7 @@ cmTarget* cmLocalGenerator::AddCustomCommandToTarget( detail::AddCustomCommandToTarget( *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, t, byproducts, depends, commandLines, type, comment, workingDir, escapeOldStyle, - uses_terminal, depfile, job_pool, command_expand_lists); + uses_terminal, depfile, job_pool, command_expand_lists, stdPipesUTF8); return t; } @@ -1039,14 +1111,14 @@ cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput( 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 std::string& depfile, const std::string& job_pool, bool stdPipesUTF8) { 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); + command_expand_lists, depfile, job_pool, stdPipesUTF8); } cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput( @@ -1057,7 +1129,7 @@ cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput( 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 std::string& job_pool, bool stdPipesUTF8) { // Make sure there is at least one output. if (outputs.empty()) { @@ -1069,7 +1141,7 @@ cmSourceFile* cmLocalGenerator::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); + command_expand_lists, depfile, job_pool, stdPipesUTF8); } cmTarget* cmLocalGenerator::AddUtilityCommand( @@ -1078,7 +1150,7 @@ cmTarget* cmLocalGenerator::AddUtilityCommand( 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) + const std::string& job_pool, bool stdPipesUTF8) { cmTarget* target = this->Makefile->AddNewUtilityTarget(utilityName, excludeFromAll); @@ -1092,7 +1164,7 @@ cmTarget* cmLocalGenerator::AddUtilityCommand( *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, target, this->Makefile->GetUtilityOutput(target), workingDir, byproducts, depends, commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists, - job_pool); + job_pool, stdPipesUTF8); return target; } @@ -1164,11 +1236,10 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit( // * Compilers like gfortran do not search their own implicit include // directories for modules ('.mod' files). if (lang != "Fortran") { - const char* value = this->Makefile->GetDefinition( - cmStrCat("CMAKE_", lang, "_IMPLICIT_INCLUDE_DIRECTORIES")); - if (value != nullptr) { - size_t const impDirVecOldSize = impDirVec.size(); - cmExpandList(value, impDirVec); + size_t const impDirVecOldSize = impDirVec.size(); + if (this->Makefile->GetDefExpandList( + cmStrCat("CMAKE_", lang, "_IMPLICIT_INCLUDE_DIRECTORIES"), + impDirVec)) { // FIXME: Use cmRange with 'advance()' when it supports non-const. for (size_t i = impDirVecOldSize; i < impDirVec.size(); ++i) { cmSystemTools::ConvertToUnixSlashes(impDirVec[i]); @@ -1183,7 +1254,7 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit( // directly. In this case adding -I/usr/include can hide SDK headers so we // must still exclude it. if ((lang == "C" || lang == "CXX" || lang == "CUDA") && - !cmContains(impDirVec, "/usr/include") && + !cm::contains(impDirVec, "/usr/include") && std::find_if(impDirVec.begin(), impDirVec.end(), [](std::string const& d) { return cmHasLiteralSuffix(d, "/usr/include"); @@ -1204,13 +1275,14 @@ 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, this->GlobalGenerator->GetRealPath(dir))) && - (!cmContains(implicitExclude, dir))) + ((!cm::contains(implicitSet, this->GlobalGenerator->GetRealPath(dir))) && + (!cm::contains(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 // user-specified directories that can be re-ordered or converted to // -isystem without breaking real compiler builtin headers. - || ((lang == "C" || lang == "CXX") && cmContains(this->EnvCPATH, dir))); + || + ((lang == "C" || lang == "CXX") && cm::contains(this->EnvCPATH, dir))); }; // Get the target-specific include directories. @@ -1257,7 +1329,7 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit( if (!stripImplicitDirs) { // Append implicit directories that were requested by the user only for (BT<std::string> const& udr : userDirs) { - if (cmContains(implicitSet, cmSystemTools::GetRealPath(udr.Value))) { + if (cm::contains(implicitSet, cmSystemTools::GetRealPath(udr.Value))) { emitBT(udr); } } @@ -1314,14 +1386,15 @@ std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags( std::string const& config, std::string const& linkLanguage, cmGeneratorTarget* target) { + const std::string configUpper = cmSystemTools::UpperCase(config); std::vector<BT<std::string>> flags; if (linkLanguage != "Swift") { std::string staticLibFlags; this->AppendFlags( staticLibFlags, this->Makefile->GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS")); - if (!config.empty()) { - std::string name = "CMAKE_STATIC_LINKER_FLAGS_" + config; + if (!configUpper.empty()) { + std::string name = "CMAKE_STATIC_LINKER_FLAGS_" + configUpper; this->AppendFlags(staticLibFlags, this->Makefile->GetSafeDefinition(name)); } @@ -1333,8 +1406,8 @@ std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags( std::string staticLibFlags; this->AppendFlags(staticLibFlags, target->GetSafeProperty("STATIC_LIBRARY_FLAGS")); - if (!config.empty()) { - std::string name = "STATIC_LIBRARY_FLAGS_" + config; + if (!configUpper.empty()) { + std::string name = "STATIC_LIBRARY_FLAGS_" + configUpper; this->AppendFlags(staticLibFlags, target->GetSafeProperty(name)); } @@ -1350,6 +1423,30 @@ std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags( return flags; } +void cmLocalGenerator::GetDeviceLinkFlags( + cmLinkLineComputer* linkLineComputer, const std::string& config, + std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath, + std::string& linkPath, cmGeneratorTarget* target) +{ + cmGeneratorTarget::DeviceLinkSetter setter(*target); + + cmComputeLinkInformation* pcli = target->GetLinkInformation(config); + const std::string linkLanguage = + linkLineComputer->GetLinkerLanguage(target, config); + + if (pcli) { + // Compute the required cuda device link libraries when + // resolving cuda device symbols + this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, frameworkPath, + linkPath); + } + + std::vector<std::string> linkOpts; + target->GetLinkOptions(linkOpts, config, linkLanguage); + // LINK_OPTIONS are escaped. + this->AppendCompileOptions(linkFlags, linkOpts); +} + void cmLocalGenerator::GetTargetFlags( cmLinkLineComputer* linkLineComputer, const std::string& config, std::string& linkLibs, std::string& flags, std::string& linkFlags, @@ -1371,23 +1468,17 @@ void cmLocalGenerator::GetTargetFlags( std::vector<BT<std::string>>& linkFlags, std::string& frameworkPath, std::vector<BT<std::string>>& linkPath, cmGeneratorTarget* target) { - const std::string buildType = cmSystemTools::UpperCase(config); + const std::string configUpper = cmSystemTools::UpperCase(config); cmComputeLinkInformation* pcli = target->GetLinkInformation(config); const char* libraryLinkVariable = "CMAKE_SHARED_LINKER_FLAGS"; // default to shared library const std::string linkLanguage = - linkLineComputer->GetLinkerLanguage(target, buildType); + linkLineComputer->GetLinkerLanguage(target, config); switch (target->GetType()) { case cmStateEnums::STATIC_LIBRARY: - linkFlags = this->GetStaticLibraryFlags(buildType, linkLanguage, target); - if (pcli && dynamic_cast<cmLinkLineDeviceComputer*>(linkLineComputer)) { - // Compute the required cuda device link libraries when - // resolving cuda device symbols - this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, - frameworkPath, linkPath); - } + linkFlags = this->GetStaticLibraryFlags(config, linkLanguage, target); break; case cmStateEnums::MODULE_LIBRARY: libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS"; @@ -1397,8 +1488,8 @@ void cmLocalGenerator::GetTargetFlags( if (linkLanguage != "Swift") { sharedLibFlags = cmStrCat( this->Makefile->GetSafeDefinition(libraryLinkVariable), ' '); - if (!buildType.empty()) { - std::string build = cmStrCat(libraryLinkVariable, '_', buildType); + if (!configUpper.empty()) { + std::string build = cmStrCat(libraryLinkVariable, '_', configUpper); sharedLibFlags += this->Makefile->GetSafeDefinition(build); sharedLibFlags += " "; } @@ -1406,30 +1497,30 @@ void cmLocalGenerator::GetTargetFlags( !(this->Makefile->IsOn("CYGWIN") || this->Makefile->IsOn("MINGW"))) { std::vector<cmSourceFile*> sources; - target->GetSourceFiles(sources, buildType); + target->GetSourceFiles(sources, config); std::string defFlag = this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); for (cmSourceFile* sf : sources) { if (sf->GetExtension() == "def") { sharedLibFlags += defFlag; - sharedLibFlags += this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(sf->ResolveFullPath()), SHELL); + sharedLibFlags += + this->ConvertToOutputFormat(sf->ResolveFullPath(), SHELL); sharedLibFlags += " "; } } } } - const char* targetLinkFlags = target->GetProperty("LINK_FLAGS"); + cmProp targetLinkFlags = target->GetProperty("LINK_FLAGS"); if (targetLinkFlags) { - sharedLibFlags += targetLinkFlags; + sharedLibFlags += *targetLinkFlags; sharedLibFlags += " "; } - if (!buildType.empty()) { + if (!configUpper.empty()) { targetLinkFlags = - target->GetProperty(cmStrCat("LINK_FLAGS_", buildType)); + target->GetProperty(cmStrCat("LINK_FLAGS_", configUpper)); if (targetLinkFlags) { - sharedLibFlags += targetLinkFlags; + sharedLibFlags += *targetLinkFlags; sharedLibFlags += " "; } } @@ -1452,9 +1543,9 @@ void cmLocalGenerator::GetTargetFlags( if (linkLanguage != "Swift") { exeFlags = this->Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS"); exeFlags += " "; - if (!buildType.empty()) { + if (!configUpper.empty()) { exeFlags += this->Makefile->GetSafeDefinition( - cmStrCat("CMAKE_EXE_LINKER_FLAGS_", buildType)); + cmStrCat("CMAKE_EXE_LINKER_FLAGS_", configUpper)); exeFlags += " "; } if (linkLanguage.empty()) { @@ -1481,7 +1572,7 @@ void cmLocalGenerator::GetTargetFlags( } } - this->AddLanguageFlagsForLinking(flags, target, linkLanguage, buildType); + this->AddLanguageFlagsForLinking(flags, target, linkLanguage, config); if (pcli) { this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, frameworkPath, linkPath); @@ -1501,16 +1592,16 @@ void cmLocalGenerator::GetTargetFlags( exeFlags += " "; } - const char* targetLinkFlags = target->GetProperty("LINK_FLAGS"); + cmProp targetLinkFlags = target->GetProperty("LINK_FLAGS"); if (targetLinkFlags) { - exeFlags += targetLinkFlags; + exeFlags += *targetLinkFlags; exeFlags += " "; } - if (!buildType.empty()) { + if (!configUpper.empty()) { targetLinkFlags = - target->GetProperty(cmStrCat("LINK_FLAGS_", buildType)); + target->GetProperty(cmStrCat("LINK_FLAGS_", configUpper)); if (targetLinkFlags) { - exeFlags += targetLinkFlags; + exeFlags += *targetLinkFlags; exeFlags += " "; } } @@ -1541,16 +1632,17 @@ void cmLocalGenerator::GetTargetFlags( void cmLocalGenerator::GetTargetCompileFlags(cmGeneratorTarget* target, std::string const& config, std::string const& lang, - std::string& flags) + std::string& flags, + std::string const& arch) { std::vector<BT<std::string>> tmpFlags = - this->GetTargetCompileFlags(target, config, lang); + this->GetTargetCompileFlags(target, config, lang, arch); this->AppendFlags(flags, tmpFlags); } std::vector<BT<std::string>> cmLocalGenerator::GetTargetCompileFlags( cmGeneratorTarget* target, std::string const& config, - std::string const& lang) + std::string const& lang, std::string const& arch) { std::vector<BT<std::string>> flags; std::string compileFlags; @@ -1564,7 +1656,7 @@ std::vector<BT<std::string>> cmLocalGenerator::GetTargetCompileFlags( this->AppendFeatureOptions(compileFlags, lang, "IPO"); } - this->AddArchitectureFlags(compileFlags, target, lang, config); + this->AddArchitectureFlags(compileFlags, target, lang, config, arch); if (lang == "Fortran") { this->AppendFlags(compileFlags, @@ -1753,10 +1845,10 @@ std::string cmLocalGenerator::GetLinkLibsCMP0065( "CMAKE_POLICY_WARNING_CMP0065")) { std::ostringstream w; /* clang-format off */ - w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0065) << "\n" - "For compatibility with older versions of CMake, " - "additional flags may be added to export symbols on all " - "executables regardless of their ENABLE_EXPORTS property."; + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0065) << "\n" + "For compatibility with older versions of CMake, " + "additional flags may be added to export symbols on all " + "executables regardless of their ENABLE_EXPORTS property."; /* clang-format on */ this->IssueMessage(MessageType::AUTHOR_WARNING, w.str()); } @@ -1812,7 +1904,8 @@ bool cmLocalGenerator::AllAppleArchSysrootsAreTheSame( void cmLocalGenerator::AddArchitectureFlags(std::string& flags, cmGeneratorTarget const* target, const std::string& lang, - const std::string& config) + const std::string& config, + const std::string& filterArch) { // Only add Apple specific flags on Apple platforms if (this->Makefile->IsOn("APPLE") && this->EmitUniversalBinaryFlags) { @@ -1821,8 +1914,10 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, 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 (filterArch.empty() || filterArch == arch) { + flags += " -arch "; + flags += arch; + } } } @@ -1841,10 +1936,12 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, if (cmIsOff(archSysroot)) { continue; } - flags += " -Xarch_" + arch + " "; - // Combine sysroot flag and path to work with -Xarch - std::string arch_sysroot = sysrootFlag + archSysroot; - flags += this->ConvertToOutputFormat(arch_sysroot, SHELL); + if (filterArch.empty() || filterArch == arch) { + flags += " -Xarch_" + arch + " "; + // Combine sysroot flag and path to work with -Xarch + std::string arch_sysroot = sysrootFlag + archSysroot; + flags += this->ConvertToOutputFormat(arch_sysroot, SHELL); + } } } else if (sysroot && *sysroot) { flags += " "; @@ -1879,28 +1976,45 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags, config); if (lang == "Swift") { - if (const char* v = target->GetProperty("Swift_LANGUAGE_VERSION")) { + if (cmProp v = target->GetProperty("Swift_LANGUAGE_VERSION")) { if (cmSystemTools::VersionCompare( cmSystemTools::OP_GREATER_EQUAL, this->Makefile->GetDefinition("CMAKE_Swift_COMPILER_VERSION"), "4.2")) { - this->AppendFlags(flags, "-swift-version " + std::string(v)); + this->AppendFlags(flags, "-swift-version " + *v); + } + } + } else if (lang == "CUDA") { + target->AddCUDAArchitectureFlags(flags); + target->AddCUDAToolkitFlags(flags); + + std::string const& compiler = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID"); + + if (compiler == "Clang") { + bool separable = target->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION"); + + if (separable) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "CUDA_SEPARABLE_COMPILATION isn't supported on Clang. " + "See CMake issue #20726."); } } } // Add MSVC runtime library flags. This is activated by the presence // of a default selection whether or not it is overridden by a property. - const char* msvcRuntimeLibraryDefault = - this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT"); - if (msvcRuntimeLibraryDefault && *msvcRuntimeLibraryDefault) { - const char* msvcRuntimeLibraryValue = + cmProp msvcRuntimeLibraryDefault = + this->Makefile->GetDef("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT"); + if (msvcRuntimeLibraryDefault && !msvcRuntimeLibraryDefault->empty()) { + cmProp msvcRuntimeLibraryValue = target->GetProperty("MSVC_RUNTIME_LIBRARY"); if (!msvcRuntimeLibraryValue) { msvcRuntimeLibraryValue = msvcRuntimeLibraryDefault; } std::string const msvcRuntimeLibrary = cmGeneratorExpression::Evaluate( - msvcRuntimeLibraryValue, this, config, target); + *msvcRuntimeLibraryValue, this, config, target); if (!msvcRuntimeLibrary.empty()) { if (const char* msvcRuntimeLibraryOptions = this->Makefile->GetDefinition( @@ -1950,6 +2064,15 @@ cmGeneratorTarget* cmLocalGenerator::FindGeneratorTargetToUse( return imported->second; } + // find local alias to imported target + auto aliased = this->AliasTargets.find(name); + if (aliased != this->AliasTargets.end()) { + imported = this->ImportedGeneratorTargets.find(aliased->second); + if (imported != this->ImportedGeneratorTargets.end()) { + return imported->second; + } + } + if (cmGeneratorTarget* t = this->FindLocalNonAliasGeneratorTarget(name)) { return t; } @@ -1973,7 +2096,6 @@ bool cmLocalGenerator::GetRealDependency(const std::string& inName, if (name.empty()) { return false; } - if (cmSystemTools::GetFilenameLastExtension(name) == ".exe") { name = cmSystemTools::GetFilenameWithoutLastExtension(name); } @@ -2013,11 +2135,9 @@ bool cmLocalGenerator::GetRealDependency(const std::string& inName, case cmStateEnums::OBJECT_LIBRARY: // An object library has no single file on which to depend. // This was listed to get the target-level dependency. - return false; case cmStateEnums::INTERFACE_LIBRARY: // An interface library has no file on which to depend. // This was listed to get the target-level dependency. - return false; case cmStateEnums::UTILITY: case cmStateEnums::GLOBAL_TARGET: // A utility target has no file on which to depend. This was listed @@ -2082,13 +2202,13 @@ void cmLocalGenerator::AddCompilerRequirementFlag( } std::string extProp = lang + "_EXTENSIONS"; bool ext = true; - if (const char* extPropValue = target->GetProperty(extProp)) { - if (cmIsOff(extPropValue)) { + if (cmProp extPropValue = target->GetProperty(extProp)) { + if (cmIsOff(*extPropValue)) { ext = false; } } std::string stdProp = lang + "_STANDARD"; - const char* standardProp = target->GetProperty(stdProp); + cmProp standardProp = target->GetProperty(stdProp); if (!standardProp) { if (ext) { // No language standard is specified and extensions are not disabled. @@ -2110,7 +2230,7 @@ void cmLocalGenerator::AddCompilerRequirementFlag( if (target->GetPropertyAsBool(lang + "_STANDARD_REQUIRED")) { std::string option_flag = - "CMAKE_" + lang + standardProp + "_" + type + "_COMPILE_OPTION"; + "CMAKE_" + lang + *standardProp + "_" + type + "_COMPILE_OPTION"; const char* opt = target->Target->GetMakefile()->GetDefinition(option_flag); @@ -2119,7 +2239,7 @@ void cmLocalGenerator::AddCompilerRequirementFlag( e << "Target \"" << target->GetName() << "\" requires the language " "dialect \"" - << lang << standardProp << "\" " + << lang << *standardProp << "\" " << (ext ? "(with compiler extensions)" : "") << ", but CMake " "does not know the compile flags to use to enable it."; @@ -2163,7 +2283,7 @@ void cmLocalGenerator::AddCompilerRequirementFlag( langStdMap["CUDA"].emplace_back("03"); } - std::string standard(standardProp); + std::string standard(*standardProp); if (lang == "CUDA" && standard == "98") { standard = "03"; } @@ -2236,7 +2356,7 @@ static void AddVisibilityCompileOption(std::string& flags, } std::string flagDefine = lang + "_VISIBILITY_PRESET"; - const char* prop = target->GetProperty(flagDefine); + cmProp prop = target->GetProperty(flagDefine); if (!prop) { return; } @@ -2244,17 +2364,17 @@ static void AddVisibilityCompileOption(std::string& flags, *warnCMP0063 += " " + flagDefine + "\n"; return; } - if (strcmp(prop, "hidden") != 0 && strcmp(prop, "default") != 0 && - strcmp(prop, "protected") != 0 && strcmp(prop, "internal") != 0) { + if ((*prop != "hidden") && (*prop != "default") && (*prop != "protected") && + (*prop != "internal")) { std::ostringstream e; - e << "Target " << target->GetName() << " uses unsupported value \"" << prop - << "\" for " << flagDefine << "." + e << "Target " << target->GetName() << " uses unsupported value \"" + << *prop << "\" for " << flagDefine << "." << " The supported values are: default, hidden, protected, and " "internal."; cmSystemTools::Error(e.str()); return; } - std::string option = std::string(opt) + prop; + std::string option = opt + *prop; lg->AppendFlags(flags, option); } @@ -2372,7 +2492,8 @@ bool cmLocalGenerator::GetShouldUseOldFlags(bool shared, std::ostringstream e; e << "Variable " << flagsVar << " has been modified. CMake " - "will ignore the POSITION_INDEPENDENT_CODE target property for " + "will ignore the POSITION_INDEPENDENT_CODE target property " + "for " "shared libraries and will use the " << flagsVar << " variable " @@ -2434,7 +2555,9 @@ void cmLocalGenerator::AddConfigVariableFlags(std::string& flags, void cmLocalGenerator::AppendFlags(std::string& flags, const std::string& newFlags) const { - if (!newFlags.empty()) { + bool allSpaces = std::all_of(newFlags.begin(), newFlags.end(), cmIsSpace); + + if (!newFlags.empty() && !allSpaces) { if (!flags.empty()) { flags += " "; } @@ -2467,10 +2590,13 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) } for (std::string const& config : configsList) { - // FIXME: Refactor collection of sources to not evaluate object libraries. + // FIXME: Refactor collection of sources to not evaluate object + // libraries. std::vector<cmSourceFile*> sources; target->GetSourceFiles(sources, config); + const std::string configUpper = cmSystemTools::UpperCase(config); + for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) { auto langSources = std::count_if( sources.begin(), sources.end(), [lang](cmSourceFile* sf) { @@ -2481,151 +2607,353 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) continue; } - const std::string pchSource = target->GetPchSource(config, lang); - const std::string pchHeader = target->GetPchHeader(config, lang); - - if (pchSource.empty() || pchHeader.empty()) { - continue; + std::vector<std::string> architectures; + if (!this->GetGlobalGenerator()->IsXcode()) { + target->GetAppleArchs(config, architectures); } + if (architectures.empty()) { + architectures.emplace_back(); + } else { + std::string useMultiArchPch; + for (const std::string& arch : architectures) { + const std::string pchHeader = + target->GetPchHeader(config, lang, arch); + if (!pchHeader.empty()) { + useMultiArchPch = cmStrCat(useMultiArchPch, ";-Xarch_", arch, + ";-include", pchHeader); + } + } - const std::string pchExtension = - this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION"); - - if (pchExtension.empty()) { - continue; + if (!useMultiArchPch.empty()) { + target->Target->SetProperty( + cmStrCat(lang, "_COMPILE_OPTIONS_USE_PCH"), useMultiArchPch); + } } - const char* pchReuseFrom = - target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); + for (const std::string& arch : architectures) { + const std::string pchSource = target->GetPchSource(config, lang, arch); + const std::string pchHeader = target->GetPchHeader(config, lang, arch); - auto pch_sf = this->Makefile->GetOrCreateSource( - pchSource, false, cmSourceFileLocationKind::Known); - - if (!this->GetGlobalGenerator()->IsXcode()) { - if (!pchReuseFrom) { - target->AddSource(pchSource, true); + if (pchSource.empty() || pchHeader.empty()) { + continue; } - const std::string pchFile = target->GetPchFile(config, lang); + const std::string pchExtension = + this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION"); - // 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); - - if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) { + if (pchExtension.empty()) { + continue; + } - const std::string pdb_prefix = - this->GetGlobalGenerator()->IsMultiConfig() - ? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/") - : ""; + cmProp ReuseFrom = + target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); - const std::string target_compile_pdb_dir = cmStrCat( - target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/", - target->GetName(), ".dir/"); + auto pch_sf = this->Makefile->GetOrCreateSource( + pchSource, false, cmSourceFileLocationKind::Known); - const std::string copy_script = - cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake"); - cmGeneratedFileStream file(copy_script); + if (!this->GetGlobalGenerator()->IsXcode()) { + if (!ReuseFrom) { + target->AddSource(pchSource, true); + } - 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 pchFile = target->GetPchFile(config, lang, arch); - const std::string to_dir = cmStrCat( - target->GetLocalGenerator()->GetCurrentBinaryDirectory(), - "/", target->GetName(), ".dir/${PDB_PREFIX}"); + // Exclude the pch files from linking + if (this->Makefile->IsOn("CMAKE_LINK_PCH")) { + if (!ReuseFrom) { + pch_sf->AppendProperty( + "OBJECT_OUTPUTS", + cmStrCat("$<$<CONFIG:", config, ">:", pchFile, ">")); + } else { + auto reuseTarget = + this->GlobalGenerator->FindGeneratorTarget(*ReuseFrom); - const std::string to_file = - cmStrCat(to_dir, pchReuseFrom, extension); + if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) { - std::string dest_file = to_file; + const std::string compilerId = + this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_COMPILER_ID")); - const std::string prefix = target->GetSafeProperty("PREFIX"); - if (!prefix.empty()) { - dest_file = - cmStrCat(to_dir, prefix, pchReuseFrom, extension); - } + const std::string compilerVersion = + this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_COMPILER_VERSION")); - 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"; + const std::string langFlags = + this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_FLAGS_", configUpper)); + + // MSVC 2008 is producing both .pdb and .idb files with /Zi. + if ((langFlags.find("/ZI") != std::string::npos || + langFlags.find("-ZI") != std::string::npos) || + (cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, + compilerVersion.c_str(), + "16.0") && + compilerId == "MSVC")) { + CopyPchCompilePdb(config, target, *ReuseFrom, reuseTarget, + { ".pdb", ".idb" }); + } else if ((langFlags.find("/Zi") != std::string::npos || + langFlags.find("-Zi") != std::string::npos)) { + CopyPchCompilePdb(config, target, *ReuseFrom, reuseTarget, + { ".pdb" }); } - file << "endif()\n"; } - 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 (reuseTarget->GetType() != cmStateEnums::OBJECT_LIBRARY) { + std::string pchSourceObj = + reuseTarget->GetPchFileObject(config, lang, arch); - target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY", - target_compile_pdb_dir); + // Link to the pch object file + target->Target->AppendProperty( + cmStrCat("LINK_FLAGS_", configUpper), + cmStrCat(" ", + this->ConvertToOutputFormat(pchSourceObj, SHELL)), + true); + } } + } else { + pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str()); + } - std::string pchSourceObj = - reuseTarget->GetPchFileObject(config, lang); + // Add pchHeader to source files, which will + // be grouped as "Precompile Header File" + auto pchHeader_sf = this->Makefile->GetOrCreateSource( + pchHeader, true, cmSourceFileLocationKind::Known); + std::string err; + pchHeader_sf->ResolveFullPath(&err); - const std::string configUpper = cmSystemTools::UpperCase(config); + // The pch file is generated, but mark it as not generated + // so that a clean operation will not remove it from disk + pchHeader_sf->SetProperty("GENERATED", "0"); - // Link to the pch object file - target->Target->AppendProperty( - cmStrCat("LINK_FLAGS_", configUpper), - cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL)), - true); - } - } else { - pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str()); + target->AddSource(pchHeader); } + } + } + } +} + +void cmLocalGenerator::CopyPchCompilePdb( + const std::string& config, cmGeneratorTarget* target, + const std::string& ReuseFrom, cmGeneratorTarget* reuseTarget, + const std::vector<std::string>& extensions) +{ + const std::string pdb_prefix = + this->GetGlobalGenerator()->IsMultiConfig() ? cmStrCat(config, "/") : ""; + + const std::string target_compile_pdb_dir = + cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/", + target->GetName(), ".dir/"); + + const std::string copy_script = + cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake"); + cmGeneratedFileStream file(copy_script); + + file << "# CMake generated file\n"; + + file << "# The compiler generated pdb file needs to be written to disk\n" + << "# by mspdbsrv. The foreach retry loop is needed to make sure\n" + << "# the pdb file is ready to be copied.\n\n"; + + for (auto const& extension : extensions) { + const std::string from_file = + cmStrCat(reuseTarget->GetLocalGenerator()->GetCurrentBinaryDirectory(), + "/", ReuseFrom, ".dir/${PDB_PREFIX}", ReuseFrom, extension); + + const std::string to_dir = + cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/", + target->GetName(), ".dir/${PDB_PREFIX}"); + + const std::string to_file = cmStrCat(to_dir, ReuseFrom, extension); + + std::string dest_file = to_file; + + std::string const& prefix = target->GetSafeProperty("PREFIX"); + if (!prefix.empty()) { + dest_file = cmStrCat(to_dir, prefix, ReuseFrom, extension); + } + + file << "foreach(retry RANGE 1 30)\n"; + file << " if (EXISTS \"" << from_file << "\" AND \"" << from_file + << " \" IS_NEWER_THAN \"" << dest_file << "\")\n"; + file << " execute_process(COMMAND ${CMAKE_COMMAND} -E copy"; + file << " \"" << from_file << "\"" + << " \"" << to_dir << "\" RESULT_VARIABLE result " + << " ERROR_QUIET)\n"; + file << " if (NOT result EQUAL 0)\n" + << " execute_process(COMMAND ${CMAKE_COMMAND}" + << " -E sleep 1)\n" + << " else()\n"; + if (!prefix.empty()) { + file << " file(REMOVE \"" << dest_file << "\")\n"; + file << " file(RENAME \"" << to_file << "\" \"" << dest_file << "\")\n"; + } + file << " break()\n" + << " endif()\n"; + file << " else()\n" + << " execute_process(COMMAND ${CMAKE_COMMAND}" + << " -E sleep 1)\n" + << " endif()\n"; + file << "endforeach()\n"; + } + + bool stdPipesUTF8 = true; + + auto configGenex = [&](cm::string_view expr) -> std::string { + if (this->GetGlobalGenerator()->IsVisualStudio()) { + return cmStrCat("$<$<CONFIG:", config, ">:", expr, ">"); + } + return std::string(expr); + }; + + cmCustomCommandLines commandLines = cmMakeSingleCommandLine( + { configGenex(cmSystemTools::GetCMakeCommand()), + configGenex(cmStrCat("-DPDB_PREFIX=", pdb_prefix)), configGenex("-P"), + configGenex(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, ReuseFrom, ".pdb")); + + if (this->GetGlobalGenerator()->IsVisualStudio()) { + this->AddCustomCommandToTarget( + target->GetName(), outputs, no_deps, commandLines, + cmCustomCommandType::PRE_BUILD, no_message, no_current_dir, true, false, + "", "", false, cmObjectLibraryCommands::Reject, stdPipesUTF8); + } 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, false, true, false, false, "", + "", stdPipesUTF8); + + if (copy_rule) { + target->AddSource(copy_rule->ResolveFullPath()); + } + } + + target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY", + target_compile_pdb_dir); +} + +namespace { + +inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf, + std::string const& filename) +{ + target->AddSourceFileToUnityBatch(sf->ResolveFullPath()); + sf->SetProperty("UNITY_SOURCE_FILE", filename.c_str()); + sf->SetProperty("SKIP_AUTOGEN", "ON"); +} + +inline void IncludeFileInUnitySources(cmGeneratedFileStream& unity_file, + std::string const& sf_full_path, + cmProp beforeInclude, + cmProp afterInclude) +{ + if (beforeInclude) { + unity_file << *beforeInclude << "\n"; + } + + unity_file << "#include \"" << sf_full_path << "\"\n"; - // 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); + if (afterInclude) { + unity_file << *afterInclude << "\n"; + } +} + +std::vector<std::string> AddUnityFilesModeAuto( + cmGeneratorTarget* target, std::string const& lang, + std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude, + cmProp afterInclude, std::string const& filename_base, size_t batchSize) +{ + if (batchSize == 0) { + batchSize = filtered_sources.size(); + } + + std::vector<std::string> unity_files; + for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0; + itemsLeft > 0; itemsLeft -= chunk, ++batch) { + + chunk = std::min(itemsLeft, batchSize); + + std::string filename = cmStrCat(filename_base, "unity_", batch, + (lang == "C") ? "_c.c" : "_cxx.cxx"); + + const std::string filename_tmp = cmStrCat(filename, ".tmp"); + { + size_t begin = batch * batchSize; + size_t end = begin + chunk; + + cmGeneratedFileStream file( + filename_tmp, false, + target->GetGlobalGenerator()->GetMakefileEncoding()); + file << "/* generated by CMake */\n\n"; + + for (; begin != end; ++begin) { + cmSourceFile* sf = filtered_sources[begin]; + RegisterUnitySources(target, sf, filename); + IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, + afterInclude); } } + cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); + unity_files.emplace_back(std::move(filename)); } + return unity_files; +} + +std::vector<std::string> AddUnityFilesModeGroup( + cmGeneratorTarget* target, std::string const& lang, + std::vector<cmSourceFile*> const& filtered_sources, cmProp beforeInclude, + cmProp afterInclude, std::string const& filename_base) +{ + std::vector<std::string> unity_files; + + // sources organized by group name. Drop any source + // without a group + std::unordered_map<std::string, std::vector<cmSourceFile*>> explicit_mapping; + for (cmSourceFile* sf : filtered_sources) { + if (cmProp value = sf->GetProperty("UNITY_GROUP")) { + auto i = explicit_mapping.find(*value); + if (i == explicit_mapping.end()) { + std::vector<cmSourceFile*> sources{ sf }; + explicit_mapping.emplace(*value, sources); + } else { + i->second.emplace_back(sf); + } + } + } + + for (auto const& item : explicit_mapping) { + auto const& name = item.first; + std::string filename = cmStrCat(filename_base, "unity_", name, + (lang == "C") ? "_c.c" : "_cxx.cxx"); + + const std::string filename_tmp = cmStrCat(filename, ".tmp"); + { + cmGeneratedFileStream file( + filename_tmp, false, + target->GetGlobalGenerator()->GetMakefileEncoding()); + file << "/* generated by CMake */\n\n"; + + for (cmSourceFile* sf : item.second) { + RegisterUnitySources(target, sf, filename); + IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, + afterInclude); + } + } + cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); + unity_files.emplace_back(std::move(filename)); + } + + return unity_files; +} } void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) @@ -2648,12 +2976,15 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) std::vector<cmSourceFile*> sources; target->GetSourceFiles(sources, config); - auto batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE"); - const size_t unityBatchSize = - static_cast<size_t>(std::atoi(batchSizeString)); + cmProp batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE"); + const size_t unityBatchSize = batchSizeString + ? static_cast<size_t>(std::atoi(batchSizeString->c_str())) + : 0; - auto beforeInclude = target->GetProperty("UNITY_BUILD_CODE_BEFORE_INCLUDE"); - auto afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE"); + cmProp beforeInclude = + target->GetProperty("UNITY_BUILD_CODE_BEFORE_INCLUDE"); + cmProp afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE"); + cmProp unityMode = target->GetProperty("UNITY_BUILD_MODE"); for (std::string lang : { "C", "CXX" }) { std::vector<cmSourceFile*> filtered_sources; @@ -2668,53 +2999,28 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) !sf->GetProperty("INCLUDE_DIRECTORIES"); }); - size_t batchSize = unityBatchSize; - if (unityBatchSize == 0) { - batchSize = filtered_sources.size(); + std::vector<std::string> unity_files; + if (!unityMode || *unityMode == "BATCH") { + unity_files = + AddUnityFilesModeAuto(target, lang, filtered_sources, beforeInclude, + afterInclude, filename_base, unityBatchSize); + } else if (unityMode && *unityMode == "GROUP") { + unity_files = + AddUnityFilesModeGroup(target, lang, filtered_sources, beforeInclude, + afterInclude, filename_base); + } else { + // unity mode is set to an unsupported value + std::string e("Invalid UNITY_BUILD_MODE value of " + *unityMode + + " assigned to target " + target->GetName() + + ". Acceptable values are BATCH and GROUP."); + this->IssueMessage(MessageType::FATAL_ERROR, e); } - for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0; - itemsLeft > 0; itemsLeft -= chunk, ++batch) { - - chunk = std::min(itemsLeft, batchSize); - - std::string filename = cmStrCat(filename_base, "unity_", batch, - (lang == "C") ? "_c.c" : "_cxx.cxx"); - - const std::string filename_tmp = cmStrCat(filename, ".tmp"); - { - size_t begin = batch * batchSize; - size_t end = begin + chunk; - - cmGeneratedFileStream file( - filename_tmp, false, - this->GetGlobalGenerator()->GetMakefileEncoding()); - file << "/* generated by CMake */\n\n"; - - for (; begin != end; ++begin) { - cmSourceFile* sf = filtered_sources[begin]; - - target->AddSourceFileToUnityBatch(sf->ResolveFullPath()); - sf->SetProperty("UNITY_SOURCE_FILE", filename.c_str()); - - if (beforeInclude) { - file << beforeInclude << "\n"; - } - - file << "#include \"" << sf->ResolveFullPath() << "\"\n"; - - if (afterInclude) { - file << afterInclude << "\n"; - } - } - } - cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); - - target->AddSource(filename, true); - - auto unity = this->Makefile->GetOrCreateSource(filename); + for (auto const& file : unity_files) { + auto unity = this->GetMakefile()->GetOrCreateSource(file); + target->AddSource(file, true); unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON"); - unity->SetProperty("UNITY_SOURCE_FILE", filename.c_str()); + unity->SetProperty("UNITY_SOURCE_FILE", file.c_str()); } } } @@ -2950,11 +3256,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 @@ -2990,16 +3296,16 @@ const char* cmLocalGenerator::GetFeature(const std::string& feature, const std::string& config) { std::string featureName = feature; - // TODO: Define accumulation policy for features (prepend, append, replace). - // Currently we always replace. + // TODO: Define accumulation policy for features (prepend, append, + // replace). Currently we always replace. if (!config.empty()) { featureName += "_"; featureName += cmSystemTools::UpperCase(config); } cmStateSnapshot snp = this->StateSnapshot; while (snp.IsValid()) { - if (const char* value = snp.GetDirectory().GetProperty(featureName)) { - return value; + if (cmProp value = snp.GetDirectory().GetProperty(featureName)) { + return value->c_str(); } snp = snp.GetBuildsystemDirectoryParent(); } @@ -3064,8 +3370,8 @@ void cmLocalGenerator::GenerateTargetInstallRules( } // Include the user-specified pre-install script for this target. - if (const char* preinstall = l->GetProperty("PRE_INSTALL_SCRIPT")) { - cmInstallScriptGenerator g(preinstall, false, "", false); + if (cmProp preinstall = l->GetProperty("PRE_INSTALL_SCRIPT")) { + cmInstallScriptGenerator g(*preinstall, false, "", false); g.Generate(os, config, configurationTypes); } @@ -3117,8 +3423,8 @@ 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, "", false); + if (cmProp postinstall = l->GetProperty("POST_INSTALL_SCRIPT")) { + cmInstallScriptGenerator g(*postinstall, false, "", false); g.Generate(os, config, configurationTypes); } } @@ -3304,11 +3610,12 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( // Select a nice-looking reference to the source file to construct // the object file name. std::string objectName; + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) if ((relSource && !relBinary) || (subSource && !subBinary)) { objectName = relFromSource; - } else if ((relBinary && !relSource) || (subBinary && !subSource)) { - objectName = relFromBinary; - } else if (relFromBinary.length() < relFromSource.length()) { + } else if ((relBinary && !relSource) || (subBinary && !subSource) || + relFromBinary.length() < relFromSource.length()) { objectName = relFromBinary; } else { objectName = relFromSource; @@ -3326,12 +3633,12 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( // Ensure that for the CMakeFiles/<target>.dir/generated_source_file // we don't end up having: // CMakeFiles/<target>.dir/CMakeFiles/<target>.dir/generated_source_file.obj - const char* unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE"); - const char* pchExtension = source.GetProperty("PCH_EXTENSION"); + cmProp unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE"); + cmProp psExtension = source.GetProperty("PCH_EXTENSION"); const bool isPchObject = objectName.find("cmake_pch") != std::string::npos; - if (unitySourceFile || pchExtension || isPchObject) { - if (pchExtension) { - customOutputExtension = pchExtension; + if (unitySourceFile || psExtension || isPchObject) { + if (psExtension) { + customOutputExtension = psExtension->c_str(); } cmsys::RegularExpression var("(CMakeFiles/[^/]+.dir/)"); @@ -3467,7 +3774,6 @@ bool cmLocalGenerator::NeedBackwardsCompatibility_2_4() break; case cmPolicies::NEW: // New behavior is to ignore the variable. - return false; case cmPolicies::REQUIRED_IF_USED: case cmPolicies::REQUIRED_ALWAYS: // This will never be the case because the only way to require @@ -3529,8 +3835,8 @@ bool cmLocalGenerator::CheckDefinition(std::string const& define) const static void cmLGInfoProp(cmMakefile* mf, cmGeneratorTarget* target, const std::string& prop) { - if (const char* val = target->GetProperty(prop)) { - mf->AddDefinition(prop, val); + if (cmProp val = target->GetProperty(prop)) { + mf->AddDefinition(prop, *val); } } @@ -3539,8 +3845,9 @@ void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target, const std::string& fname) { // Find the Info.plist template. - const char* in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST"); - std::string inFile = (in && *in) ? in : "MacOSXBundleInfo.plist.in"; + cmProp in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST"); + std::string inFile = + (in && !in->empty()) ? *in : "MacOSXBundleInfo.plist.in"; if (!cmSystemTools::FileIsFullPath(inFile)) { std::string inMod = this->Makefile->GetModulesFile(inFile); if (!inMod.empty()) { @@ -3578,8 +3885,9 @@ void cmLocalGenerator::GenerateFrameworkInfoPList( const std::string& fname) { // Find the Info.plist template. - const char* in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST"); - std::string inFile = (in && *in) ? in : "MacOSXFrameworkInfo.plist.in"; + cmProp in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST"); + std::string inFile = + (in && !in->empty()) ? *in : "MacOSXFrameworkInfo.plist.in"; if (!cmSystemTools::FileIsFullPath(inFile)) { std::string inMod = this->Makefile->GetModulesFile(inFile); if (!inMod.empty()) { @@ -3647,7 +3955,7 @@ cmSourceFile* AddCustomCommand( 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 std::string& job_pool, bool stdPipesUTF8) { cmMakefile* mf = lg.GetMakefile(); @@ -3709,7 +4017,8 @@ cmSourceFile* AddCustomCommand( } std::unique_ptr<cmCustomCommand> cc = cm::make_unique<cmCustomCommand>( - outputs, byproducts, depends2, commandLines, lfbt, comment, workingDir); + outputs, byproducts, depends2, commandLines, lfbt, comment, workingDir, + stdPipesUTF8); cc->SetEscapeOldStyle(escapeOldStyle); cc->SetEscapeAllowMakeVars(true); cc->SetImplicitDepends(implicit_depends); @@ -3736,7 +4045,7 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg, const char* workingDir, bool escapeOldStyle, bool uses_terminal, const std::string& depfile, const std::string& job_pool, - bool command_expand_lists) + bool command_expand_lists, bool stdPipesUTF8) { cmMakefile* mf = lg.GetMakefile(); @@ -3746,7 +4055,7 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg, // 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); + comment, workingDir, stdPipesUTF8); cc.SetEscapeOldStyle(escapeOldStyle); cc.SetEscapeAllowMakeVars(true); cc.SetUsesTerminal(uses_terminal); @@ -3777,7 +4086,7 @@ cmSourceFile* AddCustomCommandToOutput( 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 std::string& job_pool, bool stdPipesUTF8) { // Always create the output sources and mark them generated. CreateGeneratedSources(lg, outputs, origin, lfbt); @@ -3786,7 +4095,7 @@ cmSourceFile* AddCustomCommandToOutput( return AddCustomCommand( lg, lfbt, outputs, byproducts, depends, main_dependency, implicit_depends, commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal, - command_expand_lists, depfile, job_pool); + command_expand_lists, depfile, job_pool, stdPipesUTF8); } void AppendCustomCommandToOutput(cmLocalGenerator& lg, @@ -3822,7 +4131,7 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, const cmCustomCommandLines& commandLines, bool escapeOldStyle, const char* comment, bool uses_terminal, bool command_expand_lists, - const std::string& job_pool) + const std::string& job_pool, bool stdPipesUTF8) { // Always create the byproduct sources and mark them generated. CreateGeneratedSource(lg, force.Name, origin, lfbt); @@ -3837,9 +4146,9 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, 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); + no_implicit_depends, commandLines, comment, workingDir, + /*replace=*/false, escapeOldStyle, uses_terminal, command_expand_lists, + /*depfile=*/"", job_pool, stdPipesUTF8); if (rule) { lg.GetMakefile()->AddTargetByproducts(target, byproducts); } diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index a459384af..f2d914519 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -13,7 +13,7 @@ #include <unordered_map> #include <vector> -#include "cm_kwiml.h" +#include <cm3p/kwiml/int.h> #include "cmCustomCommandTypes.h" #include "cmListFileCache.h" @@ -105,8 +105,8 @@ public: void AddArchitectureFlags(std::string& flags, cmGeneratorTarget const* target, - const std::string& lang, - const std::string& config); + const std::string& lang, const std::string& config, + const std::string& filterArch = std::string()); void AddLanguageFlags(std::string& flags, cmGeneratorTarget const* target, const std::string& lang, const std::string& config); @@ -297,7 +297,8 @@ public: 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); + cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject, + bool stdPipesUTF8 = false); /** * Add a custom command to a source file. @@ -308,7 +309,8 @@ public: 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 = ""); + const std::string& depfile = "", const std::string& job_pool = "", + bool stdPipesUTF8 = false); cmSourceFile* AddCustomCommandToOutput( const std::vector<std::string>& outputs, const std::vector<std::string>& byproducts, @@ -318,7 +320,8 @@ public: 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 = ""); + const std::string& depfile = "", const std::string& job_pool = "", + bool stdPipesUTF8 = false); /** * Add a utility to the build. A utility target is a command that is run @@ -330,7 +333,8 @@ public: 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 = ""); + bool command_expand_lists = false, const std::string& job_pool = "", + bool stdPipesUTF8 = false); std::string GetProjectName() const; @@ -417,6 +421,11 @@ public: /** Fill out these strings for the given target. Libraries to link, * flags, and linkflags. */ + void GetDeviceLinkFlags(cmLinkLineComputer* linkLineComputer, + const std::string& config, std::string& linkLibs, + std::string& linkFlags, std::string& frameworkPath, + std::string& linkPath, cmGeneratorTarget* target); + void GetTargetFlags(cmLinkLineComputer* linkLineComputer, const std::string& config, std::string& linkLibs, std::string& flags, std::string& linkFlags, @@ -435,10 +444,11 @@ public: std::string const& lang) const; void GetTargetCompileFlags(cmGeneratorTarget* target, std::string const& config, - std::string const& lang, std::string& flags); - std::vector<BT<std::string>> GetTargetCompileFlags(cmGeneratorTarget* target, - std::string const& config, - std::string const& lang); + std::string const& lang, std::string& flags, + std::string const& arch = std::string()); + std::vector<BT<std::string>> GetTargetCompileFlags( + cmGeneratorTarget* target, std::string const& config, + std::string const& lang, std::string const& arch = std::string()); std::string GetFrameworkFlags(std::string const& l, std::string const& config, @@ -530,6 +540,11 @@ private: void ComputeObjectMaxPath(); bool AllAppleArchSysrootsAreTheSame(const std::vector<std::string>& archs, const char* sysroot); + + void CopyPchCompilePdb(const std::string& config, cmGeneratorTarget* target, + const std::string& ReuseFrom, + cmGeneratorTarget* reuseTarget, + std::vector<std::string> const& extensions); }; #if !defined(CMAKE_BOOTSTRAP) @@ -549,7 +564,7 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg, const char* workingDir, bool escapeOldStyle, bool uses_terminal, const std::string& depfile, const std::string& job_pool, - bool command_expand_lists); + bool command_expand_lists, bool stdPipesUTF8); cmSourceFile* AddCustomCommandToOutput( cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, @@ -560,7 +575,7 @@ cmSourceFile* AddCustomCommandToOutput( 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 std::string& job_pool, bool stdPipesUTF8); void AppendCustomCommandToOutput(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, @@ -577,7 +592,7 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, const cmCustomCommandLines& commandLines, bool escapeOldStyle, const char* comment, bool uses_terminal, bool command_expand_lists, - const std::string& job_pool); + const std::string& job_pool, bool stdPipesUTF8); } #endif diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 56e9f813f..87e8aa445 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -23,6 +23,7 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmNinjaTargetGenerator.h" +#include "cmProperty.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" #include "cmState.h" @@ -181,8 +182,9 @@ std::string cmLocalNinjaGenerator::ConvertToIncludeReference( bool forceFullPaths) { if (forceFullPaths) { - return this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(path), - format); + return this->ConvertToOutputFormat( + cmSystemTools::CollapseFullPath(path, this->GetCurrentBinaryDirectory()), + format); } return this->ConvertToOutputFormat( this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), path), @@ -243,9 +245,8 @@ void cmLocalNinjaGenerator::WriteBuildFileTop() void cmLocalNinjaGenerator::WriteProjectHeader(std::ostream& os) { cmGlobalNinjaGenerator::WriteDivider(os); - os << "# Project: " << this->GetProjectName() << std::endl - << "# Configurations: " << cmJoin(this->GetConfigNames(), ", ") - << std::endl; + os << "# Project: " << this->GetProjectName() << '\n' + << "# Configurations: " << cmJoin(this->GetConfigNames(), ", ") << '\n'; cmGlobalNinjaGenerator::WriteDivider(os); } @@ -272,8 +273,7 @@ void cmLocalNinjaGenerator::WriteNinjaRequiredVersion(std::ostream& os) cmGlobalNinjaGenerator::WriteComment( os, "Minimal version of Ninja required by this file"); - os << "ninja_required_version = " << requiredVersion << std::endl - << std::endl; + os << "ninja_required_version = " << requiredVersion << "\n\n"; } void cmLocalNinjaGenerator::WriteNinjaConfigurationVariable( @@ -288,23 +288,22 @@ void cmLocalNinjaGenerator::WritePools(std::ostream& os) { cmGlobalNinjaGenerator::WriteDivider(os); - const char* jobpools = + cmProp jobpools = this->GetCMakeInstance()->GetState()->GetGlobalProperty("JOB_POOLS"); if (!jobpools) { - jobpools = this->GetMakefile()->GetDefinition("CMAKE_JOB_POOLS"); + jobpools = this->GetMakefile()->GetDef("CMAKE_JOB_POOLS"); } if (jobpools) { cmGlobalNinjaGenerator::WriteComment( os, "Pools defined by global property JOB_POOLS"); - std::vector<std::string> pools = cmExpandedList(jobpools); + std::vector<std::string> pools = cmExpandedList(*jobpools); for (std::string const& pool : pools) { const std::string::size_type eq = pool.find('='); unsigned int jobs; if (eq != std::string::npos && sscanf(pool.c_str() + eq, "=%u", &jobs) == 1) { - os << "pool " << pool.substr(0, eq) << std::endl; - os << " depth = " << jobs << std::endl; - os << std::endl; + os << "pool " << pool.substr(0, eq) << "\n depth = " << jobs + << "\n\n"; } else { cmSystemTools::Error("Invalid pool defined by property 'JOB_POOLS': " + pool); @@ -316,8 +315,7 @@ void cmLocalNinjaGenerator::WritePools(std::ostream& os) void cmLocalNinjaGenerator::WriteNinjaFilesInclusionConfig(std::ostream& os) { cmGlobalNinjaGenerator::WriteDivider(os); - os << "# Include auxiliary files.\n" - << "\n"; + os << "# Include auxiliary files.\n\n"; cmGlobalNinjaGenerator* ng = this->GetGlobalNinjaGenerator(); std::string const ninjaCommonFile = ng->NinjaOutputPath(cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE); @@ -330,8 +328,7 @@ void cmLocalNinjaGenerator::WriteNinjaFilesInclusionConfig(std::ostream& os) void cmLocalNinjaGenerator::WriteNinjaFilesInclusionCommon(std::ostream& os) { cmGlobalNinjaGenerator::WriteDivider(os); - os << "# Include auxiliary files.\n" - << "\n"; + os << "# Include auxiliary files.\n\n"; cmGlobalNinjaGenerator* ng = this->GetGlobalNinjaGenerator(); std::string const ninjaRulesFile = ng->NinjaOutputPath(cmGlobalNinjaGenerator::NINJA_RULES_FILE); @@ -344,14 +341,14 @@ void cmLocalNinjaGenerator::WriteNinjaFilesInclusionCommon(std::ostream& os) void cmLocalNinjaGenerator::WriteProcessedMakefile(std::ostream& os) { cmGlobalNinjaGenerator::WriteDivider(os); - os << "# Write statements declared in CMakeLists.txt:" << std::endl + os << "# Write statements declared in CMakeLists.txt:\n" << "# " << this->Makefile->GetDefinition("CMAKE_CURRENT_LIST_FILE") - << std::endl; + << '\n'; if (this->IsRootMakefile()) { - os << "# Which is the root file." << std::endl; + os << "# Which is the root file.\n"; } cmGlobalNinjaGenerator::WriteDivider(os); - os << std::endl; + os << '\n'; } void cmLocalNinjaGenerator::AppendTargetOutputs(cmGeneratorTarget* target, @@ -669,10 +666,9 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements( std::string cmLocalNinjaGenerator::MakeCustomLauncher( cmCustomCommandGenerator const& ccg) { - const char* property_value = - this->Makefile->GetProperty("RULE_LAUNCH_CUSTOM"); + cmProp property_value = this->Makefile->GetProperty("RULE_LAUNCH_CUSTOM"); - if (!property_value || !*property_value) { + if (!property_value || property_value->empty()) { return std::string(); } @@ -694,7 +690,7 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( this->CreateRulePlaceholderExpander()); - std::string launcher = property_value; + std::string launcher = *property_value; rulePlaceholderExpander->ExpandRuleVariables(this, launcher, vars); if (!launcher.empty()) { launcher += " "; @@ -705,11 +701,11 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( void cmLocalNinjaGenerator::AdditionalCleanFiles(const std::string& config) { - if (const char* prop_value = + if (cmProp prop_value = this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) { std::vector<std::string> cleanFiles; { - cmExpandList(cmGeneratorExpression::Evaluate(prop_value, this, config), + cmExpandList(cmGeneratorExpression::Evaluate(*prop_value, this, config), cleanFiles); } std::string const& binaryDir = this->GetCurrentBinaryDirectory(); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index c9c656c0d..de1461a79 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -28,6 +28,7 @@ #include "cmMakefile.h" #include "cmMakefileTargetGenerator.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" @@ -48,37 +49,6 @@ # include "cmDependsJava.h" #endif -// Escape special characters in Makefile dependency lines -class cmMakeSafe -{ -public: - cmMakeSafe(const char* s) - : Data(s) - { - } - cmMakeSafe(std::string const& s) - : Data(s.c_str()) - { - } - -private: - const char* Data; - friend std::ostream& operator<<(std::ostream& os, cmMakeSafe const& self) - { - for (const char* c = self.Data; *c; ++c) { - switch (*c) { - case '=': - os << "$(EQUALS)"; - break; - default: - os << *c; - break; - } - } - return os; - } -}; - // Helper function used below. static std::string cmSplitExtension(std::string const& in, std::string& base) { @@ -498,6 +468,14 @@ const std::string& cmLocalUnixMakefileGenerator3::GetHomeRelativeOutputPath() return this->HomeRelativeOutputPath; } +std::string cmLocalUnixMakefileGenerator3::ConvertToMakefilePath( + std::string const& path) const +{ + cmGlobalUnixMakefileGenerator3* gg = + static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator); + return gg->ConvertToMakefilePath(path); +} + void cmLocalUnixMakefileGenerator3::WriteMakeRule( std::ostream& os, const char* comment, const std::string& target, const std::vector<std::string>& depends, @@ -528,7 +506,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( } // Construct the left hand side of the rule. - std::string tgt = cmSystemTools::ConvertToOutputPath( + std::string tgt = this->ConvertToMakefilePath( this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), target)); const char* space = ""; @@ -542,30 +520,30 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( if (symbolic) { if (const char* sym = this->Makefile->GetDefinition("CMAKE_MAKE_SYMBOLIC_RULE")) { - os << cmMakeSafe(tgt) << space << ": " << sym << "\n"; + os << tgt << space << ": " << sym << "\n"; } } // Write the rule. if (depends.empty()) { // No dependencies. The commands will always run. - os << cmMakeSafe(tgt) << space << ":\n"; + os << tgt << space << ":\n"; } else { // Split dependencies into multiple rule lines. This allows for // very long dependency lists even on older make implementations. std::string binDir = this->GetBinaryDirectory(); for (std::string const& depend : depends) { - replace = depend; - replace = cmSystemTools::ConvertToOutputPath( - this->MaybeConvertToRelativePath(binDir, replace)); - os << cmMakeSafe(tgt) << space << ": " << cmMakeSafe(replace) << "\n"; + os << tgt << space << ": " + << this->ConvertToMakefilePath( + this->MaybeConvertToRelativePath(binDir, depend)) + << '\n'; } } // Write the list of commands. os << cmWrap("\t", commands, "", "\n") << "\n"; if (symbolic && !this->IsWatcomWMake()) { - os << ".PHONY : " << cmMakeSafe(tgt) << "\n"; + os << ".PHONY : " << tgt << "\n"; } os << "\n"; // Add the output to the local help if requested. @@ -623,8 +601,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( this->MaybeConvertWatcomShellCommand(cmSystemTools::GetCMakeCommand()); if (cmakeShellCommand.empty()) { cmakeShellCommand = this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), - cmOutputConverter::SHELL); + cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); } /* clang-format off */ @@ -648,16 +625,14 @@ void cmLocalUnixMakefileGenerator3::WriteMakeVariables( << "# The top-level source directory on which CMake was run.\n" << "CMAKE_SOURCE_DIR = " << this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(this->GetSourceDirectory()), - cmOutputConverter::SHELL) + this->GetSourceDirectory(), cmOutputConverter::SHELL) << "\n" << "\n"; makefileStream << "# The top-level build directory on which CMake was run.\n" << "CMAKE_BINARY_DIR = " << this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(this->GetBinaryDirectory()), - cmOutputConverter::SHELL) + this->GetBinaryDirectory(), cmOutputConverter::SHELL) << "\n" << "\n"; /* clang-format on */ @@ -738,9 +713,10 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsTop( // "VERBOSE=1" to be added as a make variable which will change the // name of this special target. This gives a make-time choice to // the user. - this->WriteMakeRule(makefileStream, - "Suppress display of executed commands.", - "$(VERBOSE).SILENT", no_depends, no_commands, false); + // Write directly to the stream since WriteMakeRule escapes '$'. + makefileStream << "#Suppress display of executed commands.\n" + "$(VERBOSE).SILENT:\n" + "\n"; } // Work-around for makes that drop rules that have no dependencies @@ -978,7 +954,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // Expand rule variables referenced in the given launcher command. cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = target->GetName().c_str(); - vars.CMTargetType = cmState::GetTargetTypeName(target->GetType()); + vars.CMTargetType = + cmState::GetTargetTypeName(target->GetType()).c_str(); std::string output; const std::vector<std::string>& outputs = ccg.GetOutputs(); if (!outputs.empty()) { @@ -1057,10 +1034,9 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( cleanfile += filename; } cleanfile += ".cmake"; - std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile); - cmsys::ofstream fout(cleanfilePath.c_str()); + cmsys::ofstream fout(cleanfile.c_str()); if (!fout) { - cmSystemTools::Error("Could not create " + cleanfilePath); + cmSystemTools::Error("Could not create " + cleanfile); } if (!files.empty()) { fout << "file(REMOVE_RECURSE\n"; @@ -1102,10 +1078,10 @@ void cmLocalUnixMakefileGenerator3::AppendDirectoryCleanCommand( { std::vector<std::string> cleanFiles; // Look for additional files registered for cleaning in this directory. - if (const char* prop_value = + if (cmProp prop_value = this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) { cmExpandList(cmGeneratorExpression::Evaluate( - prop_value, this, + *prop_value, this, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")), cleanFiles); } @@ -1120,10 +1096,9 @@ void cmLocalUnixMakefileGenerator3::AppendDirectoryCleanCommand( cmStrCat(currentBinaryDir, "/CMakeFiles/cmake_directory_clean.cmake"); // Write clean script { - std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile); - cmsys::ofstream fout(cleanfilePath.c_str()); + cmsys::ofstream fout(cleanfile.c_str()); if (!fout) { - cmSystemTools::Error("Could not create " + cleanfilePath); + cmSystemTools::Error("Could not create " + cleanfile); return; } fout << "file(REMOVE_RECURSE\n"; @@ -1194,9 +1169,8 @@ void cmLocalUnixMakefileGenerator3::AppendEcho( color_name); if (progress) { cmd += "--progress-dir="; - cmd += this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progress->Dir), - cmOutputConverter::SHELL); + cmd += this->ConvertToOutputFormat(progress->Dir, + cmOutputConverter::SHELL); cmd += " "; cmd += "--progress-num="; cmd += progress->Arg; @@ -1331,10 +1305,9 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies( int result; if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) { if (verbose) { - std::ostringstream msg; - msg << "Dependee \"" << tgtInfo << "\" is newer than depender \"" - << internalDependFile << "\"." << std::endl; - cmSystemTools::Stdout(msg.str()); + cmSystemTools::Stdout(cmStrCat("Dependee \"", tgtInfo, + "\" is newer than depender \"", + internalDependFile, "\".\n")); } needRescanDependInfo = true; } @@ -1351,10 +1324,9 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies( if (!ftc->Compare(internalDependFile, dirInfoFile, &result) || result < 0) { if (verbose) { - std::ostringstream msg; - msg << "Dependee \"" << dirInfoFile << "\" is newer than depender \"" - << internalDependFile << "\"." << std::endl; - cmSystemTools::Stdout(msg.str()); + cmSystemTools::Stdout(cmStrCat("Dependee \"", dirInfoFile, + "\" is newer than depender \"", + internalDependFile, "\".\n")); } needRescanDirInfo = true; } @@ -1520,11 +1492,9 @@ void cmLocalUnixMakefileGenerator3::CheckMultipleOutputs(bool verbose) if (cmSystemTools::FileExists(dependee) && !cmSystemTools::FileExists(depender)) { if (verbose) { - std::ostringstream msg; - msg << "Deleting primary custom command output \"" << dependee - << "\" because another output \"" << depender - << "\" does not exist." << std::endl; - cmSystemTools::Stdout(msg.str()); + cmSystemTools::Stdout(cmStrCat( + "Deleting primary custom command output \"", dependee, + "\" because another output \"", depender, "\" does not exist.\n")); } cmSystemTools::RemoveFile(dependee); } @@ -1578,10 +1548,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( std::vector<std::string> commands; std::vector<std::string> depends; - const char* text = gt->GetProperty("EchoString"); - if (!text) { - text = "Running external command ..."; - } + cmProp p = gt->GetProperty("EchoString"); + const char* text = p ? p->c_str() : "Running external command ..."; depends.reserve(gt->GetUtilities().size()); for (BT<std::pair<std::string, bool>> const& u : gt->GetUtilities()) { depends.push_back(u.Value.first); @@ -1636,15 +1604,14 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; - progCmd << this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); + progCmd << this->ConvertToOutputFormat(progressDir, + cmOutputConverter::SHELL); std::string progressFile = "/CMakeFiles/progress.marks"; std::string progressFileNameFull = this->ConvertToFullPath(progressFile); progCmd << " " - << this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progressFileNameFull), - cmOutputConverter::SHELL); + << this->ConvertToOutputFormat(progressFileNameFull, + cmOutputConverter::SHELL); commands.push_back(progCmd.str()); } std::string mf2Dir = "CMakeFiles/Makefile2"; @@ -1654,8 +1621,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( { std::ostringstream progCmd; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 - progCmd << this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL); + progCmd << this->ConvertToOutputFormat(progressDir, + cmOutputConverter::SHELL); progCmd << " 0"; commands.push_back(progCmd.str()); } @@ -1788,7 +1755,7 @@ private: const std::string& testDir) { // First check if the test directory "starts with" the base directory: - if (testDir.find(baseDir) != 0) { + if (!cmHasPrefix(testDir, baseDir)) { return false; } // If it does, then check that it's either the same string, or that the @@ -1899,13 +1866,13 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( // Store include transform rule properties. Write the directory // rules first because they may be overridden by later target rules. std::vector<std::string> transformRules; - if (const char* xform = + if (cmProp xform = this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) { - cmExpandList(xform, transformRules); + cmExpandList(*xform, transformRules); } - if (const char* xform = + if (cmProp xform = target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) { - cmExpandList(xform, transformRules); + cmExpandList(*xform, transformRules); } if (!transformRules.empty()) { cmakefileStream << "set(CMAKE_INCLUDE_TRANSFORMS\n"; @@ -1972,7 +1939,7 @@ std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall( void cmLocalUnixMakefileGenerator3::WriteDivider(std::ostream& os) { os << "#======================================" - << "=======================================\n"; + "=======================================\n"; } void cmLocalUnixMakefileGenerator3::WriteCMakeArgument(std::ostream& os, @@ -1980,7 +1947,7 @@ void cmLocalUnixMakefileGenerator3::WriteCMakeArgument(std::ostream& os, { // Write the given string to the stream with escaping to get it back // into CMake through the lexical scanner. - os << "\""; + os << '"'; for (char c : s) { if (c == '\\') { os << "\\\\"; @@ -1990,7 +1957,7 @@ void cmLocalUnixMakefileGenerator3::WriteCMakeArgument(std::ostream& os, os << c; } } - os << "\""; + os << '"'; } std::string cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath( diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 68eeb2942..2b07952bb 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -46,6 +46,12 @@ public: // local generators StartOutputDirectory const std::string& GetHomeRelativeOutputPath(); + /** + * Convert a file path to a Makefile target or dependency with + * escaping and quoting suitable for the generator's make tool. + */ + std::string ConvertToMakefilePath(std::string const& path) const; + // Write out a make rule void WriteMakeRule(std::ostream& os, const char* comment, const std::string& target, diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx index 02e2c6d16..9076e26d1 100644 --- a/Source/cmLocalVisualStudio10Generator.cxx +++ b/Source/cmLocalVisualStudio10Generator.cxx @@ -4,7 +4,7 @@ #include <cmext/algorithm> -#include "cm_expat.h" +#include <cm3p/expat.h> #include "cmAlgorithms.h" #include "cmGeneratorTarget.h" diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 9aa39914a..5d50e2d2b 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -2,12 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmLocalVisualStudio7Generator.h" +#include <cm/memory> +#include <cmext/algorithm> + #include <windows.h> +#include <cm3p/expat.h> #include <ctype.h> // for isspace -#include "cm_expat.h" - #include "cmComputeLinkInformation.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" @@ -18,6 +20,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmSourceFile.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmXMLParser.h" #include "cmake.h" @@ -52,14 +55,11 @@ 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() { @@ -69,9 +69,9 @@ void cmLocalVisualStudio7Generator::AddHelperCommands() if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - const char* path = l->GetProperty("EXTERNAL_MSPROJECT"); + cmProp path = l->GetProperty("EXTERNAL_MSPROJECT"); if (path) { - this->ReadAndStoreExternalGUID(l->GetName(), path); + this->ReadAndStoreExternalGUID(l->GetName(), path->c_str()); } } @@ -226,7 +226,6 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() std::string makefileIn = cmStrCat(this->GetCurrentSourceDirectory(), "/CMakeLists.txt"); - makefileIn = cmSystemTools::CollapseFullPath(makefileIn); if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) { if (file->GetCustomCommand()) { return file; @@ -252,15 +251,15 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() std::string argB = cmStrCat("-B", this->GetBinaryDirectory()); std::string stampName = cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/generate.stamp"); + bool stdPipesUTF8 = true; cmCustomCommandLines commandLines = cmMakeSingleCommandLine({ cmSystemTools::GetCMakeCommand(), argS, argB, "--check-stamp-file", stampName }); std::string comment = cmStrCat("Building Custom Rule ", makefileIn); const char* no_working_directory = nullptr; - std::string fullpathStampName = cmSystemTools::CollapseFullPath(stampName); - this->AddCustomCommandToOutput(fullpathStampName, listFiles, makefileIn, - commandLines, comment.c_str(), - no_working_directory, true, false); + this->AddCustomCommandToOutput( + stampName, listFiles, makefileIn, commandLines, comment.c_str(), + no_working_directory, true, false, false, false, "", "", stdPipesUTF8); 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. @@ -284,6 +283,7 @@ void cmLocalVisualStudio7Generator::WriteConfigurations( } cmVS7FlagTable cmLocalVisualStudio7GeneratorFortranFlagTable[] = { { "Preprocess", "fpp", "Run Preprocessor on files", "preprocessYes", 0 }, + { "Preprocess", "nofpp", "Run Preprocessor on files", "preprocessNo", 0 }, { "SuppressStartupBanner", "nologo", "SuppressStartupBanner", "true", 0 }, { "SourceFileFormat", "fixed", "Use Fixed Format", "fileFormatFixed", 0 }, { "SourceFileFormat", "free", "Use Free Format", "fileFormatFree", 0 }, @@ -672,7 +672,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( if (this->FortranProject) { switch (cmOutputConverter::GetFortranFormat( - target->GetProperty("Fortran_FORMAT"))) { + target->GetSafeProperty("Fortran_FORMAT"))) { case cmOutputConverter::FortranFormatFixed: flags += " -fixed"; break; @@ -682,6 +682,18 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( default: break; } + + switch (cmOutputConverter::GetFortranPreprocess( + target->GetSafeProperty("Fortran_PREPROCESS"))) { + case cmOutputConverter::FortranPreprocess::Needed: + flags += " -fpp"; + break; + case cmOutputConverter::FortranPreprocess::NotNeeded: + flags += " -nofpp"; + break; + default: + break; + } } // Get preprocessor definitions for this directory. @@ -778,12 +790,11 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( fout << "\t\t\t<Tool\n" << "\t\t\t\tName=\"" << tool << "\"\n"; if (this->FortranProject) { - const char* target_mod_dir = - target->GetProperty("Fortran_MODULE_DIRECTORY"); + cmProp target_mod_dir = target->GetProperty("Fortran_MODULE_DIRECTORY"); std::string modDir; if (target_mod_dir) { modDir = this->MaybeConvertToRelativePath( - this->GetCurrentBinaryDirectory(), target_mod_dir); + this->GetCurrentBinaryDirectory(), *target_mod_dir); } else { modDir = "."; } @@ -937,17 +948,17 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( " " + GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName); } - const char* targetLinkFlags = target->GetProperty("LINK_FLAGS"); + cmProp targetLinkFlags = target->GetProperty("LINK_FLAGS"); if (targetLinkFlags) { extraLinkOptions += " "; - extraLinkOptions += targetLinkFlags; + extraLinkOptions += *targetLinkFlags; } std::string configTypeUpper = cmSystemTools::UpperCase(configName); std::string linkFlagsConfig = cmStrCat("LINK_FLAGS_", configTypeUpper); targetLinkFlags = target->GetProperty(linkFlagsConfig); if (targetLinkFlags) { extraLinkOptions += " "; - extraLinkOptions += targetLinkFlags; + extraLinkOptions += *targetLinkFlags; } std::vector<std::string> opts; @@ -1006,9 +1017,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( } } std::string libflags; - this->GetStaticLibraryFlags(libflags, configTypeUpper, - target->GetLinkerLanguage(configName), - target); + this->GetStaticLibraryFlags( + libflags, configName, target->GetLinkerLanguage(configName), target); if (!libflags.empty()) { fout << "\t\t\t\tAdditionalOptions=\"" << libflags << "\"\n"; } @@ -1206,8 +1216,8 @@ void cmLocalVisualStudio7Generator::OutputDeploymentDebuggerTool( std::ostream& fout, std::string const& config, cmGeneratorTarget* target) { if (this->WindowsCEProject) { - const char* dir = target->GetProperty("DEPLOYMENT_REMOTE_DIRECTORY"); - const char* additionalFiles = + cmProp dir = target->GetProperty("DEPLOYMENT_REMOTE_DIRECTORY"); + cmProp additionalFiles = target->GetProperty("DEPLOYMENT_ADDITIONAL_FILES"); if (dir == nullptr && additionalFiles == nullptr) { @@ -1217,15 +1227,15 @@ void cmLocalVisualStudio7Generator::OutputDeploymentDebuggerTool( fout << "\t\t\t<DeploymentTool\n" "\t\t\t\tForceDirty=\"-1\"\n" "\t\t\t\tRemoteDirectory=\"" - << GetEscapedPropertyIfValueNotNULL(dir) + << GetEscapedPropertyIfValueNotNULL(dir->c_str()) << "\"\n" "\t\t\t\tRegisterOutput=\"0\"\n" "\t\t\t\tAdditionalFiles=\"" - << GetEscapedPropertyIfValueNotNULL(additionalFiles) << "\"/>\n"; + << GetEscapedPropertyIfValueNotNULL(additionalFiles->c_str()) + << "\"/>\n"; if (dir != nullptr) { - std::string const exe = - dir + std::string("\\") + target->GetFullName(config); + std::string const exe = *dir + "\\" + target->GetFullName(config); fout << "\t\t\t<DebuggerTool\n" "\t\t\t\tRemoteExecutable=\"" @@ -1448,14 +1458,15 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( needfc = true; } const std::string COMPILE_FLAGS("COMPILE_FLAGS"); - if (const char* cflags = sf.GetProperty(COMPILE_FLAGS)) { - fc.CompileFlags = genexInterpreter.Evaluate(cflags, COMPILE_FLAGS); + if (cmProp cflags = sf.GetProperty(COMPILE_FLAGS)) { + fc.CompileFlags = genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS); needfc = true; } const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); - if (const char* coptions = sf.GetProperty(COMPILE_OPTIONS)) { + if (cmProp coptions = sf.GetProperty(COMPILE_OPTIONS)) { lg->AppendCompileOptions( - fc.CompileFlags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); + fc.CompileFlags, + genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS)); needfc = true; } // Add precompile headers compile options. @@ -1475,8 +1486,22 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( } if (lg->FortranProject) { + switch (cmOutputConverter::GetFortranPreprocess( + sf.GetSafeProperty("Fortran_PREPROCESS"))) { + case cmOutputConverter::FortranPreprocess::Needed: + fc.CompileFlags = cmStrCat("-fpp ", fc.CompileFlags); + needfc = true; + break; + case cmOutputConverter::FortranPreprocess::NotNeeded: + fc.CompileFlags = cmStrCat("-nofpp ", fc.CompileFlags); + needfc = true; + break; + default: + break; + } + switch (cmOutputConverter::GetFortranFormat( - sf.GetProperty("Fortran_FORMAT"))) { + sf.GetSafeProperty("Fortran_FORMAT"))) { case cmOutputConverter::FortranFormatFixed: fc.CompileFlags = "-fixed " + fc.CompileFlags; needfc = true; @@ -1490,31 +1515,30 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( } } const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); - if (const char* cdefs = sf.GetProperty(COMPILE_DEFINITIONS)) { - fc.CompileDefs = genexInterpreter.Evaluate(cdefs, COMPILE_DEFINITIONS); + if (cmProp cdefs = sf.GetProperty(COMPILE_DEFINITIONS)) { + fc.CompileDefs = genexInterpreter.Evaluate(*cdefs, COMPILE_DEFINITIONS); needfc = true; } std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper); - if (const char* ccdefs = sf.GetProperty(defPropName)) { + if (cmProp ccdefs = sf.GetProperty(defPropName)) { fc.CompileDefsConfig = - genexInterpreter.Evaluate(ccdefs, COMPILE_DEFINITIONS); + genexInterpreter.Evaluate(*ccdefs, COMPILE_DEFINITIONS); needfc = true; } const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); - if (const char* cincs = sf.GetProperty(INCLUDE_DIRECTORIES)) { - fc.IncludeDirs = genexInterpreter.Evaluate(cincs, INCLUDE_DIRECTORIES); + if (cmProp cincs = sf.GetProperty(INCLUDE_DIRECTORIES)) { + fc.IncludeDirs = genexInterpreter.Evaluate(*cincs, INCLUDE_DIRECTORIES); needfc = true; } // Check for extra object-file dependencies. - if (const char* deps = sf.GetProperty("OBJECT_DEPENDS")) { - std::vector<std::string> depends = cmExpandedList(deps); + if (cmProp 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); + fc.AdditionalDeps += lg->ConvertToXMLOutputPath(d); sep = ";"; needfc = true; } @@ -1524,7 +1548,7 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( // If HEADER_FILE_ONLY is set, we must suppress this generation in // the project file fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") || - !cmContains(acs.Configs, ci) || + !cm::contains(acs.Configs, ci) || (gt->GetPropertyAsBool("UNITY_BUILD") && sf.GetProperty("UNITY_SOURCE_FILE") && !sf.GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION")); @@ -1877,20 +1901,20 @@ void cmLocalVisualStudio7Generator::WriteProjectSCC(std::ostream& fout, { // if we have all the required Source code control tags // then add that to the project - const char* vsProjectname = target->GetProperty("VS_SCC_PROJECTNAME"); - const char* vsLocalpath = target->GetProperty("VS_SCC_LOCALPATH"); - const char* vsProvider = target->GetProperty("VS_SCC_PROVIDER"); + cmProp vsProjectname = target->GetProperty("VS_SCC_PROJECTNAME"); + cmProp vsLocalpath = target->GetProperty("VS_SCC_LOCALPATH"); + cmProp vsProvider = target->GetProperty("VS_SCC_PROVIDER"); if (vsProvider && vsLocalpath && vsProjectname) { /* clang-format off */ - fout << "\tSccProjectName=\"" << vsProjectname << "\"\n" - << "\tSccLocalPath=\"" << vsLocalpath << "\"\n" - << "\tSccProvider=\"" << vsProvider << "\"\n"; + fout << "\tSccProjectName=\"" << *vsProjectname << "\"\n" + << "\tSccLocalPath=\"" << *vsLocalpath << "\"\n" + << "\tSccProvider=\"" << *vsProvider << "\"\n"; /* clang-format on */ - const char* vsAuxPath = target->GetProperty("VS_SCC_AUXPATH"); + cmProp vsAuxPath = target->GetProperty("VS_SCC_AUXPATH"); if (vsAuxPath) { - fout << "\tSccAuxPath=\"" << vsAuxPath << "\"\n"; + fout << "\tSccAuxPath=\"" << *vsAuxPath << "\"\n"; } } } @@ -1908,10 +1932,8 @@ void cmLocalVisualStudio7Generator::WriteProjectStartFortran( << "\tProjectCreator=\"Intel Fortran\"\n" << "\tVersion=\"" << gg->GetIntelProjectVersion() << "\"\n"; /* clang-format on */ - const char* keyword = target->GetProperty("VS_KEYWORD"); - if (!keyword) { - keyword = "Console Application"; - } + cmProp p = target->GetProperty("VS_KEYWORD"); + const char* keyword = p ? p->c_str() : "Console Application"; const char* projectType = 0; switch (target->GetType()) { case cmStateEnums::STATIC_LIBRARY: @@ -1970,20 +1992,16 @@ void cmLocalVisualStudio7Generator::WriteProjectStart( << "\tProjectType=\"Visual C++\"\n"; /* clang-format on */ fout << "\tVersion=\"" << (gg->GetVersion() / 10) << ".00\"\n"; - const char* projLabel = target->GetProperty("PROJECT_LABEL"); - if (!projLabel) { - projLabel = libName.c_str(); - } - const char* keyword = target->GetProperty("VS_KEYWORD"); - if (!keyword) { - keyword = "Win32Proj"; - } + cmProp p = target->GetProperty("PROJECT_LABEL"); + const std::string projLabel = p ? *p : libName; + p = target->GetProperty("VS_KEYWORD"); + const std::string keyword = p ? *p : "Win32Proj"; fout << "\tName=\"" << projLabel << "\"\n"; fout << "\tProjectGUID=\"{" << gg->GetGUID(libName) << "}\"\n"; this->WriteProjectSCC(fout, target); - if (const char* targetFrameworkVersion = + if (cmProp targetFrameworkVersion = target->GetProperty("VS_DOTNET_TARGET_FRAMEWORK_VERSION")) { - fout << "\tTargetFrameworkVersion=\"" << targetFrameworkVersion << "\"\n"; + fout << "\tTargetFrameworkVersion=\"" << *targetFrameworkVersion << "\"\n"; } /* clang-format off */ fout << "\tKeyword=\"" << keyword << "\">\n" @@ -2010,7 +2028,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFooter( fout << "\t<Globals>\n"; for (std::string const& key : target->GetPropertyKeys()) { - if (key.find("VS_GLOBAL_") == 0) { + if (cmHasLiteralPrefix(key, "VS_GLOBAL_")) { std::string name = key.substr(10); if (!name.empty()) { /* clang-format off */ diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 745766ce7..8b9b8ad2a 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> @@ -48,6 +49,10 @@ public: virtual ~cmLocalVisualStudio7Generator(); + cmLocalVisualStudio7Generator(const cmLocalVisualStudio7Generator&) = delete; + const cmLocalVisualStudio7Generator& operator=( + const cmLocalVisualStudio7Generator&) = delete; + void AddHelperCommands() override; /** @@ -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 8d508980e..ebd4f96a1 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -102,10 +102,12 @@ cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmGeneratorTarget* target, std::vector<std::string> no_output; std::vector<std::string> no_byproducts; std::vector<std::string> no_depends; + bool stdPipesUTF8 = true; cmCustomCommandLines commands = cmMakeSingleCommandLine( { cmSystemTools::GetCMakeCommand(), "-E", "make_directory", impDir }); pcc.reset(new cmCustomCommand(no_output, no_byproducts, no_depends, commands, - cmListFileBacktrace(), nullptr, nullptr)); + cmListFileBacktrace(), nullptr, nullptr, + stdPipesUTF8)); pcc->SetEscapeOldStyle(false); pcc->SetEscapeAllowMakeVars(true); return pcc; @@ -154,8 +156,7 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( script += newline; newline = newline_text; script += "cd "; - script += this->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(workingDirectory), SHELL); + script += this->ConvertToOutputFormat(workingDirectory, SHELL); script += check_error; // Change the working drive. diff --git a/Source/cmMachO.cxx b/Source/cmMachO.cxx index 6cbed36d9..53112e061 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 0b0d9ac31..c88b34318 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -8,8 +8,7 @@ #include <cm/memory> #include <cm/string_view> #include <cmext/algorithm> - -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmExecutionStatus.h" #include "cmFunctionBlocker.h" diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 18689fa5f..db5cee9bd 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -18,15 +18,16 @@ #include <cm/optional> #include <cm/vector> #include <cmext/algorithm> +#include <cmext/string_view> + +#include <cm3p/json/value.h> +#include <cm3p/json/writer.h> #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" #include "cmCommandArgumentParserHelper.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" @@ -61,6 +62,7 @@ #include "cmake.h" #ifndef CMAKE_BOOTSTRAP +# include "cmMakefileProfilingData.h" # include "cmVariableWatch.h" #endif @@ -373,19 +375,30 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const class cmMakefileCall { public: - cmMakefileCall(cmMakefile* mf, cmCommandContext const& cc, + cmMakefileCall(cmMakefile* mf, cmListFileFunction const& lff, cmExecutionStatus& status) : Makefile(mf) { cmListFileContext const& lfc = cmListFileContext::FromCommandContext( - cc, this->Makefile->StateSnapshot.GetExecutionListFile()); + lff, this->Makefile->StateSnapshot.GetExecutionListFile()); this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc); ++this->Makefile->RecursionDepth; this->Makefile->ExecutionStatusStack.push_back(&status); +#if !defined(CMAKE_BOOTSTRAP) + if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) { + this->Makefile->GetCMakeInstance()->GetProfilingOutput().StartEntry(lff, + lfc); + } +#endif } ~cmMakefileCall() { +#if !defined(CMAKE_BOOTSTRAP) + if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) { + this->Makefile->GetCMakeInstance()->GetProfilingOutput().StopEntry(); + } +#endif this->Makefile->ExecutionStatusStack.pop_back(); --this->Makefile->RecursionDepth; this->Makefile->Backtrace = this->Makefile->Backtrace.Pop(); @@ -685,6 +698,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) { @@ -988,7 +1022,7 @@ 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) + bool command_expand_lists, bool stdPipesUTF8) { cmTarget* t = this->GetCustomCommandTarget( target, cmObjectLibraryCommands::Reject, this->Backtrace); @@ -1006,14 +1040,15 @@ cmTarget* cmMakefile::AddCustomCommandToTarget( 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); - }); + 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, stdPipesUTF8); + }); return t; } @@ -1024,14 +1059,14 @@ void cmMakefile::AddCustomCommandToOutput( 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) + const std::string& job_pool, bool stdPipesUTF8) { std::vector<std::string> no_byproducts; cmImplicitDependsList no_implicit_depends; 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); + uses_terminal, command_expand_lists, depfile, job_pool, stdPipesUTF8); } void cmMakefile::AddCustomCommandToOutput( @@ -1042,7 +1077,7 @@ void cmMakefile::AddCustomCommandToOutput( const cmCustomCommandLines& commandLines, 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) + const std::string& depfile, const std::string& job_pool, bool stdPipesUTF8) { // Make sure there is at least one output. if (outputs.empty()) { @@ -1064,18 +1099,19 @@ void cmMakefile::AddCustomCommandToOutput( 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); - } - }); + 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, + stdPipesUTF8); + if (callback && sf) { + callback(sf); + } + }); } void cmMakefile::AddCustomCommandOldStyle( @@ -1191,7 +1227,7 @@ cmTarget* cmMakefile::AddUtilityCommand( 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) + const std::string& job_pool, bool stdPipesUTF8) { cmTarget* target = this->AddNewUtilityTarget(utilityName, excludeFromAll); @@ -1220,7 +1256,7 @@ cmTarget* cmMakefile::AddUtilityCommand( force, GetCStrOrNull(workingStr), byproducts, depends, commandLines, escapeOldStyle, GetCStrOrNull(commentStr), uses_terminal, - command_expand_lists, job_pool); + command_expand_lists, job_pool, stdPipesUTF8); }); return target; @@ -1358,9 +1394,9 @@ bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove) const char* define = def.c_str() + 2; if (remove) { - if (const char* cdefs = this->GetProperty("COMPILE_DEFINITIONS")) { + if (cmProp cdefs = this->GetProperty("COMPILE_DEFINITIONS")) { // Expand the list. - std::vector<std::string> defs = cmExpandedList(cdefs); + std::vector<std::string> defs = cmExpandedList(*cdefs); // Recompose the list without the definition. auto defEnd = std::remove(defs.begin(), defs.end(), define); @@ -1389,29 +1425,32 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent) // Include transform property. There is no per-config version. { const char* prop = "IMPLICIT_DEPENDS_INCLUDE_TRANSFORM"; - this->SetProperty(prop, parent->GetProperty(prop)); + cmProp p = parent->GetProperty(prop); + this->SetProperty(prop, p ? p->c_str() : nullptr); } // compile definitions property and per-config versions cmPolicies::PolicyStatus polSt = this->GetPolicyStatus(cmPolicies::CMP0043); if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) { - this->SetProperty("COMPILE_DEFINITIONS", - parent->GetProperty("COMPILE_DEFINITIONS")); + cmProp p = parent->GetProperty("COMPILE_DEFINITIONS"); + this->SetProperty("COMPILE_DEFINITIONS", p ? p->c_str() : nullptr); std::vector<std::string> configs; this->GetConfigurations(configs); for (std::string const& config : configs) { std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config)); - const char* prop = parent->GetProperty(defPropName); - this->SetProperty(defPropName, prop); + cmProp prop = parent->GetProperty(defPropName); + this->SetProperty(defPropName, prop ? prop->c_str() : nullptr); } } // labels - this->SetProperty("LABELS", parent->GetProperty("LABELS")); + cmProp p = parent->GetProperty("LABELS"); + this->SetProperty("LABELS", p ? p->c_str() : nullptr); // link libraries - this->SetProperty("LINK_LIBRARIES", parent->GetProperty("LINK_LIBRARIES")); + p = parent->GetProperty("LINK_LIBRARIES"); + this->SetProperty("LINK_LIBRARIES", p ? p->c_str() : nullptr); // the initial project name this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName()); @@ -1422,6 +1461,9 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent) // Imported targets. this->ImportedTargets = parent->ImportedTargets; + // Non-global Alias targets. + this->AliasTargets = parent->AliasTargets; + // Recursion depth. this->RecursionDepth = parent->RecursionDepth; } @@ -1606,7 +1648,7 @@ void cmMakefile::Configure() allowedCommands.insert("message"); isProblem = false; for (cmListFileFunction const& func : listFile.Functions) { - if (!cmContains(allowedCommands, func.Name.Lower)) { + if (!cm::contains(allowedCommands, func.Name.Lower)) { isProblem = true; break; } @@ -1842,8 +1884,7 @@ void cmMakefile::AddCacheDefinition(const std::string& name, const char* value, cmStateEnums::CacheEntryType type, bool force) { - const std::string* existingValue = - this->GetState()->GetInitializedCacheValue(name); + cmProp existingValue = this->GetState()->GetInitializedCacheValue(name); // must be outside the following if() to keep it alive long enough std::string nvalue; @@ -1973,8 +2014,8 @@ void cmMakefile::AddGlobalLinkInformation(cmTarget& target) default:; } - if (const char* linkLibsProp = this->GetProperty("LINK_LIBRARIES")) { - std::vector<std::string> linkLibs = cmExpandedList(linkLibsProp); + if (cmProp linkLibsProp = this->GetProperty("LINK_LIBRARIES")) { + std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp); for (auto j = linkLibs.begin(); j != linkLibs.end(); ++j) { std::string libraryName = *j; @@ -1997,10 +2038,13 @@ void cmMakefile::AddGlobalLinkInformation(cmTarget& target) } } -void cmMakefile::AddAlias(const std::string& lname, std::string const& tgtName) +void cmMakefile::AddAlias(const std::string& lname, std::string const& tgtName, + bool globallyVisible) { this->AliasTargets[lname] = tgtName; - this->GetGlobalGenerator()->AddAlias(lname, tgtName); + if (globallyVisible) { + this->GetGlobalGenerator()->AddAlias(lname, tgtName); + } } cmTarget* cmMakefile::AddLibrary(const std::string& lname, @@ -2043,11 +2087,11 @@ cmTarget* cmMakefile::AddExecutable(const std::string& exeName, cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type, const std::string& name) { - auto it = - this->Targets - .emplace(name, - cmTarget(name, type, cmTarget::VisibilityNormal, this, true)) - .first; + auto it = this->Targets + .emplace(name, + cmTarget(name, type, cmTarget::VisibilityNormal, this, + cmTarget::PerConfig::Yes)) + .first; this->OrderedTargets.push_back(&it->second); this->GetGlobalGenerator()->IndexTarget(&it->second); this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name); @@ -2366,11 +2410,11 @@ cmSourceGroup* cmMakefile::GetOrCreateSourceGroup( cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(const std::string& name) { - const char* delimiter = this->GetDefinition("SOURCE_GROUP_DELIMITER"); - if (delimiter == nullptr) { - delimiter = "\\"; + const char* delimiters = this->GetDefinition("SOURCE_GROUP_DELIMITER"); + if (delimiters == nullptr) { + delimiters = "/\\"; } - return this->GetOrCreateSourceGroup(cmTokenize(name, delimiter)); + return this->GetOrCreateSourceGroup(cmTokenize(name, delimiters)); } /** @@ -2418,14 +2462,14 @@ void cmMakefile::ExpandVariablesCMP0019() } std::ostringstream w; - const char* includeDirs = this->GetProperty("INCLUDE_DIRECTORIES"); - if (mightExpandVariablesCMP0019(includeDirs)) { - std::string dirs = includeDirs; + cmProp includeDirs = this->GetProperty("INCLUDE_DIRECTORIES"); + if (includeDirs && mightExpandVariablesCMP0019(includeDirs->c_str())) { + std::string dirs = *includeDirs; this->ExpandVariablesInString(dirs, true, true); - if (pol == cmPolicies::WARN && dirs != includeDirs) { + if (pol == cmPolicies::WARN && dirs != *includeDirs) { /* clang-format off */ w << "Evaluated directory INCLUDE_DIRECTORIES\n" - << " " << includeDirs << "\n" + << " " << *includeDirs << "\n" << "as\n" << " " << dirs << "\n"; /* clang-format on */ @@ -2441,13 +2485,13 @@ void cmMakefile::ExpandVariablesCMP0019() continue; } includeDirs = t.GetProperty("INCLUDE_DIRECTORIES"); - if (mightExpandVariablesCMP0019(includeDirs)) { - std::string dirs = includeDirs; + if (includeDirs && mightExpandVariablesCMP0019(includeDirs->c_str())) { + std::string dirs = *includeDirs; this->ExpandVariablesInString(dirs, true, true); - if (pol == cmPolicies::WARN && dirs != includeDirs) { + if (pol == cmPolicies::WARN && dirs != *includeDirs) { /* clang-format off */ w << "Evaluated target " << t.GetName() << " INCLUDE_DIRECTORIES\n" - << " " << includeDirs << "\n" + << " " << *includeDirs << "\n" << "as\n" << " " << dirs << "\n"; /* clang-format on */ @@ -2456,10 +2500,10 @@ void cmMakefile::ExpandVariablesCMP0019() } } - if (const char* linkDirsProp = this->GetProperty("LINK_DIRECTORIES")) { - if (mightExpandVariablesCMP0019(linkDirsProp)) { - std::string d = linkDirsProp; - std::string orig = linkDirsProp; + if (cmProp linkDirsProp = this->GetProperty("LINK_DIRECTORIES")) { + if (mightExpandVariablesCMP0019(linkDirsProp->c_str())) { + std::string d = *linkDirsProp; + const std::string orig = d; this->ExpandVariablesInString(d, true, true); if (pol == cmPolicies::WARN && d != orig) { /* clang-format off */ @@ -2472,20 +2516,17 @@ void cmMakefile::ExpandVariablesCMP0019() } } - if (const char* linkLibsProp = this->GetProperty("LINK_LIBRARIES")) { - std::vector<std::string> linkLibs = cmExpandedList(linkLibsProp); + if (cmProp linkLibsProp = this->GetProperty("LINK_LIBRARIES")) { + std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp); for (auto l = linkLibs.begin(); l != linkLibs.end(); ++l) { std::string libName = *l; - if (libName == "optimized") { - ++l; - libName = *l; - } else if (libName == "debug") { + if (libName == "optimized"_s || libName == "debug"_s) { ++l; libName = *l; } if (mightExpandVariablesCMP0019(libName.c_str())) { - std::string orig = libName; + const std::string orig = libName; this->ExpandVariablesInString(libName, true, true); if (pol == cmPolicies::WARN && libName != orig) { /* clang-format off */ @@ -2589,7 +2630,7 @@ cmMakefile::AppleSDK cmMakefile::GetAppleSDKType() const }; for (auto const& entry : sdkDatabase) { - if (sdkRoot.find(entry.name) == 0 || + if (cmHasPrefix(sdkRoot, entry.name) || sdkRoot.find(std::string("/") + entry.name) != std::string::npos) { return entry.sdk; } @@ -2647,7 +2688,7 @@ const std::string& cmMakefile::GetRequiredDefinition( bool cmMakefile::IsDefinitionSet(const std::string& name) const { - const std::string* def = this->StateSnapshot.GetDefinition(name); + cmProp def = this->StateSnapshot.GetDefinition(name); if (!def) { def = this->GetState()->GetInitializedCacheValue(name); } @@ -2664,7 +2705,7 @@ bool cmMakefile::IsDefinitionSet(const std::string& name) const const std::string* cmMakefile::GetDef(const std::string& name) const { - const std::string* def = this->StateSnapshot.GetDefinition(name); + cmProp def = this->StateSnapshot.GetDefinition(name); if (!def) { def = this->GetState()->GetInitializedCacheValue(name); } @@ -2710,6 +2751,18 @@ const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const return *def; } +bool cmMakefile::GetDefExpandList(const std::string& name, + std::vector<std::string>& out, + bool emptyArgs) const +{ + cmProp def = this->GetDef(name); + if (!def) { + return false; + } + cmExpandList(*def, out, emptyArgs); + return true; +} + std::vector<std::string> cmMakefile::GetDefinitions() const { std::vector<std::string> res = this->StateSnapshot.ClosureKeys(); @@ -2998,7 +3051,7 @@ MessageType cmMakefile::ExpandVariablesInStringNew( openstack.pop_back(); result.append(last, in - last); std::string const& lookup = result.substr(var.loc); - const char* value = nullptr; + cmProp value = nullptr; std::string varresult; std::string svalue; switch (var.domain) { @@ -3006,12 +3059,12 @@ MessageType cmMakefile::ExpandVariablesInStringNew( if (filename && lookup == lineVar) { varresult = std::to_string(line); } else { - value = this->GetDefinition(lookup); + value = this->GetDef(lookup); } break; case ENVIRONMENT: if (cmSystemTools::GetEnv(lookup, svalue)) { - value = svalue.c_str(); + value = &svalue; } break; case CACHE: @@ -3021,9 +3074,9 @@ MessageType cmMakefile::ExpandVariablesInStringNew( // Get the string we're meant to append to. if (value) { if (escapeQuotes) { - varresult = cmEscapeQuotes(value); + varresult = cmEscapeQuotes(*value); } else { - varresult = value; + varresult = *value; } } else if (!this->SuppressSideEffects) { this->MaybeWarnUninitialized(lookup, filename); @@ -3238,10 +3291,7 @@ std::string cmMakefile::GetConfigurations(std::vector<std::string>& configs, bool singleConfig) const { if (this->GetGlobalGenerator()->IsMultiConfig()) { - if (const char* configTypes = - this->GetDefinition("CMAKE_CONFIGURATION_TYPES")) { - cmExpandList(configTypes, configs); - } + this->GetDefExpandList("CMAKE_CONFIGURATION_TYPES", configs); return ""; } const std::string& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); @@ -4051,7 +4101,7 @@ void cmMakefile::AppendProperty(const std::string& prop, this->Backtrace); } -const char* cmMakefile::GetProperty(const std::string& prop) const +cmProp cmMakefile::GetProperty(const std::string& prop) const { // Check for computed properties. static std::string output; @@ -4064,20 +4114,21 @@ const char* cmMakefile::GetProperty(const std::string& prop) const return pair.first; }); output = cmJoin(keys, ";"); - return output.c_str(); + return &output; } return this->StateSnapshot.GetDirectory().GetProperty(prop); } -const char* cmMakefile::GetProperty(const std::string& prop, bool chain) const +cmProp cmMakefile::GetProperty(const std::string& prop, bool chain) const { return this->StateSnapshot.GetDirectory().GetProperty(prop, chain); } bool cmMakefile::GetPropertyAsBool(const std::string& prop) const { - return cmIsOn(this->GetProperty(prop)); + cmProp p = this->GetProperty(prop); + return p && cmIsOn(*p); } std::vector<std::string> cmMakefile::GetPropertyKeys() const @@ -4129,8 +4180,8 @@ void cmMakefile::GetTests(const std::string& config, void cmMakefile::AddCMakeDependFilesFromUser() { std::vector<std::string> deps; - if (const char* deps_str = this->GetProperty("CMAKE_CONFIGURE_DEPENDS")) { - cmExpandList(deps_str, deps); + if (cmProp deps_str = this->GetProperty("CMAKE_CONFIGURE_DEPENDS")) { + cmExpandList(*deps_str, deps); } for (std::string const& dep : deps) { if (cmSystemTools::FileIsFullPath(dep)) { @@ -4225,7 +4276,7 @@ cmTarget* cmMakefile::AddImportedTarget(const std::string& name, new cmTarget(name, type, global ? cmTarget::VisibilityImportedGlobally : cmTarget::VisibilityImported, - this, true)); + this, cmTarget::PerConfig::Yes)); // Add to the set of available imported targets. this->ImportedTargets[name] = target.get(); @@ -4241,7 +4292,15 @@ cmTarget* cmMakefile::FindTargetToUse(const std::string& name, { // Look for an imported target. These take priority because they // are more local in scope and do not have to be globally unique. - auto imported = this->ImportedTargets.find(name); + auto targetName = name; + if (!excludeAliases) { + // Look for local alias targets. + auto alias = this->AliasTargets.find(name); + if (alias != this->AliasTargets.end()) { + targetName = alias->second; + } + } + auto imported = this->ImportedTargets.find(targetName); if (imported != this->ImportedTargets.end()) { return imported->second; } @@ -4257,7 +4316,7 @@ cmTarget* cmMakefile::FindTargetToUse(const std::string& name, bool cmMakefile::IsAlias(const std::string& name) const { - if (cmContains(this->AliasTargets, name)) { + if (cm::contains(this->AliasTargets, name)) { return true; } return this->GetGlobalGenerator()->IsAlias(name); @@ -4498,7 +4557,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::CMP0069 && + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0071 && !(this->GetCMakeInstance()->GetIsInTryCompile() && ( // Policies set by cmCoreTryCompile::TryCompileCode. @@ -4627,7 +4686,7 @@ bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, } std::vector<std::string> availableFeatures = cmExpandedList(features); - if (!cmContains(availableFeatures, feature)) { + if (!cm::contains(availableFeatures, feature)) { std::ostringstream e; e << "The compiler feature \"" << feature << "\" is not known to " << lang << " compiler\n\"" @@ -4763,8 +4822,8 @@ bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, const std::string& feature, std::string const& lang) const { - const char* defaultCStandard = - this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); + cmProp defaultCStandard = + this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); if (!defaultCStandard) { this->IssueMessage( MessageType::INTERNAL_ERROR, @@ -4775,11 +4834,11 @@ bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, return true; } if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), - cmStrCmp(defaultCStandard)) == cm::cend(C_STANDARDS)) { + cmStrCmp(*defaultCStandard)) == cm::cend(C_STANDARDS)) { const std::string e = cmStrCat("The CMAKE_", lang, "_STANDARD_DEFAULT variable contains an " "invalid value: \"", - defaultCStandard, "\"."); + *defaultCStandard, "\"."); this->IssueMessage(MessageType::INTERNAL_ERROR, e); return false; } @@ -4790,24 +4849,23 @@ bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, this->CheckNeededCLanguage(feature, lang, needC90, needC99, needC11); - const char* existingCStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCStandard = target->GetProperty(cmStrCat(lang, "_STANDARD")); if (!existingCStandard) { existingCStandard = defaultCStandard; } if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), - cmStrCmp(existingCStandard)) == cm::cend(C_STANDARDS)) { + cmStrCmp(*existingCStandard)) == cm::cend(C_STANDARDS)) { const std::string e = cmStrCat( "The ", lang, "_STANDARD property on target \"", target->GetName(), - "\" contained an invalid value: \"", existingCStandard, "\"."); + "\" contained an invalid value: \"", *existingCStandard, "\"."); this->IssueMessage(MessageType::FATAL_ERROR, e); return false; } const char* const* existingCIt = existingCStandard ? std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), - cmStrCmp(existingCStandard)) + cmStrCmp(*existingCStandard)) : cm::cend(C_STANDARDS); if (needC11 && existingCStandard && @@ -4858,8 +4916,8 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, const std::string& feature, std::string const& lang) const { - const char* defaultCxxStandard = - this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); + cmProp defaultCxxStandard = + this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); if (!defaultCxxStandard) { this->IssueMessage( MessageType::INTERNAL_ERROR, @@ -4870,10 +4928,10 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, return true; } if (std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), - cmStrCmp(defaultCxxStandard)) == cm::cend(CXX_STANDARDS)) { + cmStrCmp(*defaultCxxStandard)) == cm::cend(CXX_STANDARDS)) { const std::string e = cmStrCat("The CMAKE_", lang, "_STANDARD_DEFAULT variable contains an ", - "invalid value: \"", defaultCxxStandard, "\"."); + "invalid value: \"", *defaultCxxStandard, "\"."); this->IssueMessage(MessageType::INTERNAL_ERROR, e); return false; } @@ -4886,7 +4944,7 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, this->CheckNeededCxxLanguage(feature, lang, needCxx98, needCxx11, needCxx14, needCxx17, needCxx20); - const char* existingCxxStandard = + cmProp existingCxxStandard = target->GetProperty(cmStrCat(lang, "_STANDARD")); if (!existingCxxStandard) { existingCxxStandard = defaultCxxStandard; @@ -4894,11 +4952,11 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, const char* const* existingCxxLevel = std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), - cmStrCmp(existingCxxStandard)); + cmStrCmp(*existingCxxStandard)); if (existingCxxLevel == cm::cend(CXX_STANDARDS)) { const std::string e = cmStrCat( "The ", lang, "_STANDARD property on target \"", target->GetName(), - "\" contained an invalid value: \"", existingCxxStandard, "\"."); + "\" contained an invalid value: \"", *existingCxxStandard, "\"."); this->IssueMessage(MessageType::FATAL_ERROR, e); return false; } @@ -4925,27 +4983,27 @@ void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, if (const char* propCxx98 = this->GetDefinition(cmStrCat("CMAKE_", lang, "98_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propCxx98); - needCxx98 = cmContains(props, feature); + needCxx98 = cm::contains(props, feature); } if (const char* propCxx11 = this->GetDefinition(cmStrCat("CMAKE_", lang, "11_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propCxx11); - needCxx11 = cmContains(props, feature); + needCxx11 = cm::contains(props, feature); } if (const char* propCxx14 = this->GetDefinition(cmStrCat("CMAKE_", lang, "14_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propCxx14); - needCxx14 = cmContains(props, feature); + needCxx14 = cm::contains(props, feature); } if (const char* propCxx17 = this->GetDefinition(cmStrCat("CMAKE_", lang, "17_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propCxx17); - needCxx17 = cmContains(props, feature); + needCxx17 = cm::contains(props, feature); } if (const char* propCxx20 = this->GetDefinition(cmStrCat("CMAKE_", lang, "20_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propCxx20); - needCxx20 = cmContains(props, feature); + needCxx20 = cm::contains(props, feature); } } @@ -4963,12 +5021,12 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, this->CheckNeededCxxLanguage(feature, lang, needCxx98, needCxx11, needCxx14, needCxx17, needCxx20); - const char* existingCxxStandard = + cmProp existingCxxStandard = target->GetProperty(cmStrCat(lang, "_STANDARD")); if (existingCxxStandard == nullptr) { - const char* defaultCxxStandard = - this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); - if (defaultCxxStandard && *defaultCxxStandard) { + cmProp defaultCxxStandard = + this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); + if (defaultCxxStandard && !defaultCxxStandard->empty()) { existingCxxStandard = defaultCxxStandard; } } @@ -4976,11 +5034,11 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, if (existingCxxStandard) { existingCxxLevel = std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), - cmStrCmp(existingCxxStandard)); + cmStrCmp(*existingCxxStandard)); if (existingCxxLevel == cm::cend(CXX_STANDARDS)) { const std::string e = cmStrCat( "The ", lang, "_STANDARD property on target \"", target->GetName(), - "\" contained an invalid value: \"", existingCxxStandard, "\"."); + "\" contained an invalid value: \"", *existingCxxStandard, "\"."); if (error) { *error = e; } else { @@ -5016,8 +5074,8 @@ 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")); + cmProp defaultCudaStandard = + this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); if (!defaultCudaStandard) { this->IssueMessage( MessageType::INTERNAL_ERROR, @@ -5028,11 +5086,11 @@ bool cmMakefile::HaveCudaStandardAvailable(cmTarget const* target, return true; } if (std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), - cmStrCmp(defaultCudaStandard)) == + cmStrCmp(*defaultCudaStandard)) == cm::cend(CUDA_STANDARDS)) { const std::string e = cmStrCat("The CMAKE_", lang, "_STANDARD_DEFAULT variable contains an ", - "invalid value: \"", defaultCudaStandard, "\"."); + "invalid value: \"", *defaultCudaStandard, "\"."); this->IssueMessage(MessageType::INTERNAL_ERROR, e); return false; } @@ -5045,7 +5103,7 @@ bool cmMakefile::HaveCudaStandardAvailable(cmTarget const* target, this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11, needCuda14, needCuda17, needCuda20); - const char* existingCudaStandard = + cmProp existingCudaStandard = target->GetProperty(cmStrCat(lang, "_STANDARD")); if (!existingCudaStandard) { existingCudaStandard = defaultCudaStandard; @@ -5053,11 +5111,11 @@ bool cmMakefile::HaveCudaStandardAvailable(cmTarget const* target, const char* const* existingCudaLevel = std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), - cmStrCmp(existingCudaStandard)); + 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, "\"."); + "\" contained an invalid value: \"", *existingCudaStandard, "\"."); this->IssueMessage(MessageType::FATAL_ERROR, e); return false; } @@ -5084,27 +5142,27 @@ void cmMakefile::CheckNeededCudaLanguage(const std::string& feature, if (const char* propCuda03 = this->GetDefinition(cmStrCat("CMAKE_", lang, "03_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propCuda03); - needCuda03 = cmContains(props, feature); + needCuda03 = cm::contains(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); + needCuda11 = cm::contains(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); + needCuda14 = cm::contains(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); + needCuda17 = cm::contains(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); + needCuda20 = cm::contains(props, feature); } } @@ -5122,12 +5180,12 @@ bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11, needCuda14, needCuda17, needCuda20); - const char* existingCudaStandard = + cmProp existingCudaStandard = target->GetProperty(cmStrCat(lang, "_STANDARD")); if (existingCudaStandard == nullptr) { - const char* defaultCudaStandard = - this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); - if (defaultCudaStandard && *defaultCudaStandard) { + cmProp defaultCudaStandard = + this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); + if (defaultCudaStandard && !defaultCudaStandard->empty()) { existingCudaStandard = defaultCudaStandard; } } @@ -5135,11 +5193,11 @@ bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, if (existingCudaStandard) { existingCudaLevel = std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), - cmStrCmp(existingCudaStandard)); + 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, "\"."); + "\" contained an invalid value: \"", *existingCudaStandard, "\"."); if (error) { *error = e; } else { @@ -5178,17 +5236,17 @@ void cmMakefile::CheckNeededCLanguage(const std::string& feature, if (const char* propC90 = this->GetDefinition(cmStrCat("CMAKE_", lang, "90_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propC90); - needC90 = cmContains(props, feature); + needC90 = cm::contains(props, feature); } if (const char* propC99 = this->GetDefinition(cmStrCat("CMAKE_", lang, "99_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propC99); - needC99 = cmContains(props, feature); + needC99 = cm::contains(props, feature); } if (const char* propC11 = this->GetDefinition(cmStrCat("CMAKE_", lang, "11_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propC11); - needC11 = cmContains(props, feature); + needC11 = cm::contains(props, feature); } } @@ -5203,21 +5261,20 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, this->CheckNeededCLanguage(feature, lang, needC90, needC99, needC11); - const char* existingCStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); + cmProp existingCStandard = target->GetProperty(cmStrCat(lang, "_STANDARD")); if (existingCStandard == nullptr) { - const char* defaultCStandard = - this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); - if (defaultCStandard && *defaultCStandard) { + cmProp defaultCStandard = + this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); + if (defaultCStandard && !defaultCStandard->empty()) { existingCStandard = defaultCStandard; } } if (existingCStandard) { if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), - cmStrCmp(existingCStandard)) == cm::cend(C_STANDARDS)) { + cmStrCmp(*existingCStandard)) == cm::cend(C_STANDARDS)) { const std::string e = cmStrCat( "The ", lang, "_STANDARD property on target \"", target->GetName(), - "\" contained an invalid value: \"", existingCStandard, "\"."); + "\" contained an invalid value: \"", *existingCStandard, "\"."); if (error) { *error = e; } else { @@ -5229,7 +5286,7 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, } const char* const* existingCIt = existingCStandard ? std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), - cmStrCmp(existingCStandard)) + cmStrCmp(*existingCStandard)) : cm::cend(C_STANDARDS); bool setC90 = needC90 && !existingCStandard; diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index d918abe36..45d7109e1 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -26,6 +26,7 @@ #include "cmMessageType.h" #include "cmNewLineStyle.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmSourceFileLocationKind.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" @@ -117,6 +118,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); @@ -183,7 +187,8 @@ public: 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); + const std::string& job_pool = "", bool command_expand_lists = false, + bool stdPipesUTF8 = false); /** * Called for each file with custom command. @@ -200,7 +205,8 @@ public: 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 = ""); + const std::string& depfile = "", const std::string& job_pool = "", + bool stdPipesUTF8 = false); void AddCustomCommandToOutput( const std::vector<std::string>& outputs, const std::vector<std::string>& byproducts, @@ -211,7 +217,8 @@ public: 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 = ""); + const std::string& depfile = "", const std::string& job_pool = "", + bool stdPipesUTF8 = false); void AddCustomCommandOldStyle(const std::string& target, const std::vector<std::string>& outputs, const std::vector<std::string>& depends, @@ -279,7 +286,8 @@ public: 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 = ""); + bool command_expand_lists = false, const std::string& job_pool = "", + bool stdPipesUTF8 = false); /** * Add a subdirectory to the build. @@ -314,6 +322,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 @@ -342,7 +356,8 @@ public: cmStateEnums::TargetType type, const std::vector<std::string>& srcs, bool excludeFromAll = false); - void AddAlias(const std::string& libname, const std::string& tgt); + void AddAlias(const std::string& libname, const std::string& tgt, + bool globallyVisible = true); //@{ /** @@ -408,7 +423,8 @@ public: } const char* GetIncludeRegularExpression() const { - return this->GetProperty("INCLUDE_REGULAR_EXPRESSION"); + cmProp p = this->GetProperty("INCLUDE_REGULAR_EXPRESSION"); + return p ? p->c_str() : nullptr; } /** @@ -497,6 +513,8 @@ public: const std::string& GetSafeDefinition(const std::string&) const; const std::string& GetRequiredDefinition(const std::string& name) const; bool IsDefinitionSet(const std::string&) const; + bool GetDefExpandList(const std::string& name, std::vector<std::string>& out, + bool emptyArgs = false) const; /** * Get the list of all variables in the current space. If argument * cacheonly is specified and is greater than 0, then only cache @@ -786,8 +804,8 @@ public: void SetProperty(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; + cmProp GetProperty(const std::string& prop) const; + cmProp GetProperty(const std::string& prop, bool chain) const; bool GetPropertyAsBool(const std::string& prop) const; std::vector<std::string> GetPropertyKeys() const; diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 0471a459e..446f225bd 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -122,31 +122,15 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( } // Build a list of compiler flags and linker flags. - std::string flags; + std::string langFlags; std::string linkFlags; - // Add flags to create an executable. - // Add symbol export flags if necessary. - if (this->GeneratorTarget->IsExecutableWithExports()) { - std::string export_flag_var = - cmStrCat("CMAKE_EXE_EXPORTS_", linkLanguage, "_FLAG"); - this->LocalGenerator->AppendFlags( - linkFlags, this->Makefile->GetSafeDefinition(export_flag_var)); - } - - this->LocalGenerator->AppendFlags(linkFlags, - this->LocalGenerator->GetLinkLibsCMP0065( - linkLanguage, *this->GeneratorTarget)); - // Add language feature flags. this->LocalGenerator->AddLanguageFlagsForLinking( - flags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); + langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); - this->LocalGenerator->AddArchitectureFlags( - flags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); - - // Add target-specific linker flags. - this->GetTargetLinkFlags(linkFlags, linkLanguage); + // Add device-specific linker flags. + this->GetDeviceLinkFlags(linkFlags, linkLanguage); // Construct a list of files associated with this executable that // may need to be cleaned. @@ -226,7 +210,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( vars.ObjectDir = objectDir.c_str(); vars.Target = target.c_str(); vars.LinkLibraries = linkLibs.c_str(); - vars.Flags = flags.c_str(); + vars.LanguageCompileFlags = langFlags.c_str(); vars.LinkFlags = linkFlags.c_str(); vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); @@ -494,9 +478,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // add it now. std::string implibRuleVar = cmStrCat("CMAKE_", linkLanguage, "_CREATE_IMPORT_LIBRARY"); - if (const char* rule = this->Makefile->GetDefinition(implibRuleVar)) { - cmExpandList(rule, real_link_commands); - } + this->Makefile->GetDefExpandList(implibRuleVar, real_link_commands); } bool useResponseFileForObjects = @@ -547,7 +529,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GeneratorTarget->GetName().c_str(); vars.CMTargetType = - cmState::GetTargetTypeName(this->GeneratorTarget->GetType()); + cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str(); vars.Language = linkLanguage.c_str(); vars.Objects = buildObjs.c_str(); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index d3f3a4ff0..5809b4a5c 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -141,8 +141,7 @@ void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules() std::string extraFlags; this->LocalGenerator->GetStaticLibraryFlags( - extraFlags, cmSystemTools::UpperCase(this->GetConfigName()), linkLanguage, - this->GeneratorTarget); + extraFlags, this->GetConfigName(), linkLanguage, this->GeneratorTarget); this->WriteLibraryRules(linkRuleVar, extraFlags, false); } @@ -250,9 +249,14 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( std::vector<std::string> depends; this->AppendLinkDepends(depends, linkLanguage); + // Add language-specific flags. + std::string langFlags; + this->LocalGenerator->AddLanguageFlagsForLinking( + langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); + // Create set of linking flags. std::string linkFlags; - this->GetTargetLinkFlags(linkFlags, linkLanguage); + this->GetDeviceLinkFlags(linkFlags, linkLanguage); // Get the name of the device object to generate. std::string const targetOutputReal = @@ -345,16 +349,10 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( vars.Target = target.c_str(); vars.LinkLibraries = linkLibs.c_str(); vars.ObjectsQuoted = buildObjs.c_str(); + vars.LanguageCompileFlags = langFlags.c_str(); vars.LinkFlags = linkFlags.c_str(); vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); - // Add language-specific flags. - std::string langFlags; - this->LocalGenerator->AddLanguageFlagsForLinking( - langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); - - vars.LanguageCompileFlags = langFlags.c_str(); - std::string launcher; const char* val = this->LocalGenerator->GetRuleLauncher( this->GeneratorTarget, "RULE_LAUNCH_LINK"); @@ -644,27 +642,21 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( arCreateVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( arCreateVar, linkLanguage, this->GetConfigName()); - if (const char* rule = this->Makefile->GetDefinition(arCreateVar)) { - cmExpandList(rule, archiveCreateCommands); - } + this->Makefile->GetDefExpandList(arCreateVar, archiveCreateCommands); std::string arAppendVar = cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_APPEND"); arAppendVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( arAppendVar, linkLanguage, this->GetConfigName()); - if (const char* rule = this->Makefile->GetDefinition(arAppendVar)) { - cmExpandList(rule, archiveAppendCommands); - } + this->Makefile->GetDefExpandList(arAppendVar, archiveAppendCommands); std::string arFinishVar = cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_FINISH"); arFinishVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( arFinishVar, linkLanguage, this->GetConfigName()); - if (const char* rule = this->Makefile->GetDefinition(arFinishVar)) { - cmExpandList(rule, archiveFinishCommands); - } + this->Makefile->GetDefExpandList(arFinishVar, archiveFinishCommands); } // Decide whether to use archiving rules. @@ -756,7 +748,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.CMTargetName = this->GeneratorTarget->GetName().c_str(); vars.CMTargetType = - cmState::GetTargetTypeName(this->GeneratorTarget->GetType()); + cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str(); vars.Language = linkLanguage.c_str(); vars.AIXExports = aixExports.c_str(); vars.Objects = buildObjs.c_str(); diff --git a/Source/cmMakefileProfilingData.cxx b/Source/cmMakefileProfilingData.cxx new file mode 100644 index 000000000..29fd44051 --- /dev/null +++ b/Source/cmMakefileProfilingData.cxx @@ -0,0 +1,114 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmMakefileProfilingData.h" + +#include <chrono> +#include <stdexcept> +#include <vector> + +#include <cm3p/json/value.h> +#include <cm3p/json/writer.h> + +#include "cmsys/FStream.hxx" +#include "cmsys/SystemInformation.hxx" + +#include "cmListFileCache.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +cmMakefileProfilingData::cmMakefileProfilingData( + const std::string& profileStream) +{ + std::ios::openmode omode = std::ios::out | std::ios::trunc; + this->ProfileStream.open(profileStream.c_str(), omode); + Json::StreamWriterBuilder wbuilder; + this->JsonWriter = + std::unique_ptr<Json::StreamWriter>(wbuilder.newStreamWriter()); + if (!this->ProfileStream.good()) { + throw std::runtime_error(std::string("Unable to open: ") + profileStream); + } + + this->ProfileStream << "["; +}; + +cmMakefileProfilingData::~cmMakefileProfilingData() noexcept +{ + if (this->ProfileStream.good()) { + try { + this->ProfileStream << "]"; + this->ProfileStream.close(); + } catch (...) { + cmSystemTools::Error("Error writing profiling output!"); + } + } +} + +void cmMakefileProfilingData::StartEntry(const cmListFileFunction& lff, + cmListFileContext const& lfc) +{ + /* Do not try again if we previously failed to write to output. */ + if (!this->ProfileStream.good()) { + return; + } + + try { + if (this->ProfileStream.tellp() > 1) { + this->ProfileStream << ","; + } + cmsys::SystemInformation info; + Json::Value v; + v["ph"] = "B"; + v["name"] = lff.Name.Lower; + v["cat"] = "cmake"; + v["ts"] = Json::Value::UInt64( + std::chrono::duration_cast<std::chrono::microseconds>( + std::chrono::steady_clock::now().time_since_epoch()) + .count()); + v["pid"] = static_cast<int>(info.GetProcessId()); + v["tid"] = 0; + Json::Value argsValue; + if (!lff.Arguments.empty()) { + std::string args; + for (const auto& a : lff.Arguments) { + args += (args.empty() ? "" : " ") + a.Value; + } + argsValue["functionArgs"] = args; + } + argsValue["location"] = lfc.FilePath + ":" + std::to_string(lfc.Line); + v["args"] = argsValue; + + this->JsonWriter->write(v, &this->ProfileStream); + } catch (std::ios_base::failure& fail) { + cmSystemTools::Error( + cmStrCat("Failed to write to profiling output: ", fail.what())); + } catch (...) { + cmSystemTools::Error("Error writing profiling output!"); + } +} + +void cmMakefileProfilingData::StopEntry() +{ + /* Do not try again if we previously failed to write to output. */ + if (!this->ProfileStream.good()) { + return; + } + + try { + this->ProfileStream << ","; + cmsys::SystemInformation info; + Json::Value v; + v["ph"] = "E"; + v["ts"] = Json::Value::UInt64( + std::chrono::duration_cast<std::chrono::microseconds>( + std::chrono::steady_clock::now().time_since_epoch()) + .count()); + v["pid"] = static_cast<int>(info.GetProcessId()); + v["tid"] = 0; + this->JsonWriter->write(v, &this->ProfileStream); + } catch (std::ios_base::failure& fail) { + cmSystemTools::Error( + cmStrCat("Failed to write to profiling output:", fail.what())); + } catch (...) { + cmSystemTools::Error("Error writing profiling output!"); + } +} diff --git a/Source/cmMakefileProfilingData.h b/Source/cmMakefileProfilingData.h new file mode 100644 index 000000000..1babd97eb --- /dev/null +++ b/Source/cmMakefileProfilingData.h @@ -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. */ +#ifndef cmMakefileProfilingData_h +#define cmMakefileProfilingData_h +#include <memory> +#include <string> + +#include "cmsys/FStream.hxx" + +namespace Json { +class StreamWriter; +} + +class cmListFileContext; +struct cmListFileFunction; + +class cmMakefileProfilingData +{ +public: + cmMakefileProfilingData(const std::string&); + ~cmMakefileProfilingData() noexcept; + void StartEntry(const cmListFileFunction& lff, cmListFileContext const& lfc); + void StopEntry(); + +private: + cmsys::ofstream ProfileStream; + std::unique_ptr<Json::StreamWriter> JsonWriter; +}; +#endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index a8769d8be..8396fa326 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -5,6 +5,7 @@ #include <cassert> #include <cstdio> #include <sstream> +#include <unordered_map> #include <utility> #include <cm/memory> @@ -17,7 +18,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" -#include "cmLinkLineComputer.h" +#include "cmLinkLineComputer.h" // IWYU pragma: keep #include "cmLocalCommonGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" @@ -25,6 +26,7 @@ #include "cmMakefileLibraryTargetGenerator.h" #include "cmMakefileUtilityTargetGenerator.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" @@ -46,9 +48,8 @@ cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target) this->LocalGenerator->GetGlobalGenerator()); cmake* cm = this->GlobalGenerator->GetCMakeInstance(); this->NoRuleMessages = false; - if (const char* ruleStatus = - cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) { - this->NoRuleMessages = cmIsOff(ruleStatus); + if (cmProp ruleStatus = cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) { + this->NoRuleMessages = cmIsOff(*ruleStatus); } MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this); } @@ -87,6 +88,18 @@ std::string cmMakefileTargetGenerator::GetConfigName() return configNames.front(); } +void cmMakefileTargetGenerator::GetDeviceLinkFlags( + std::string& linkFlags, const std::string& linkLanguage) +{ + cmGeneratorTarget::DeviceLinkSetter setter(*this->GetGeneratorTarget()); + + std::vector<std::string> linkOpts; + this->GeneratorTarget->GetLinkOptions(linkOpts, this->GetConfigName(), + linkLanguage); + // LINK_OPTIONS are escaped. + this->LocalGenerator->AppendCompileOptions(linkFlags, linkOpts); +} + void cmMakefileTargetGenerator::GetTargetLinkFlags( std::string& flags, const std::string& linkLanguage) { @@ -155,7 +168,7 @@ 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->GetConfigName(), @@ -165,16 +178,16 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() }; // Look for additional files registered for cleaning in this directory. - if (const char* prop_value = + if (cmProp prop_value = this->Makefile->GetProperty("ADDITIONAL_MAKE_CLEAN_FILES")) { - std::vector<std::string> const files = evaluatedFiles(prop_value); + std::vector<std::string> const files = evaluatedFiles(*prop_value); this->CleanFiles.insert(files.begin(), files.end()); } // Look for additional files registered for cleaning in this target. - if (const char* prop_value = + if (cmProp prop_value = this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) { - std::vector<std::string> const files = evaluatedFiles(prop_value); + std::vector<std::string> const files = evaluatedFiles(*prop_value); // For relative path support std::string const& binaryDir = this->LocalGenerator->GetCurrentBinaryDirectory(); @@ -184,8 +197,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() } // add custom commands to the clean rules? - const char* clean_no_custom = this->Makefile->GetProperty("CLEAN_NO_CUSTOM"); - bool clean = cmIsOff(clean_no_custom); + cmProp clean_no_custom = this->Makefile->GetProperty("CLEAN_NO_CUSTOM"); + bool clean = clean_no_custom ? cmIsOff(*clean_no_custom) : true; // First generate the object rule files. Save a list of all object // files for this target. @@ -300,8 +313,7 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() dependFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding()); depFileStream << "# Empty dependencies file for " << this->GeneratorTarget->GetName() << ".\n" - << "# This may be replaced when dependencies are built." - << std::endl; + << "# This may be replaced when dependencies are built.\n"; } // Open the flags file. This should be copy-if-different because the @@ -342,17 +354,32 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() << "\n"; } + bool const escapeOctothorpe = this->GlobalGenerator->CanEscapeOctothorpe(); + for (std::string const& language : languages) { - 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, "#", "\\#"); - cmSystemTools::ReplaceString(includes, "#", "\\#"); - *this->FlagFileStream << language << "_FLAGS = " << flags << "\n\n"; + if (escapeOctothorpe) { + // Escape comment characters so they do not terminate assignment. + cmSystemTools::ReplaceString(defines, "#", "\\#"); + cmSystemTools::ReplaceString(includes, "#", "\\#"); + } *this->FlagFileStream << language << "_DEFINES = " << defines << "\n\n"; *this->FlagFileStream << language << "_INCLUDES = " << includes << "\n\n"; + + std::vector<std::string> architectures; + this->GeneratorTarget->GetAppleArchs(this->GetConfigName(), architectures); + architectures.emplace_back(); + + for (const std::string& arch : architectures) { + std::string flags = + this->GetFlags(language, this->GetConfigName(), arch); + if (escapeOctothorpe) { + cmSystemTools::ReplaceString(flags, "#", "\\#"); + } + *this->FlagFileStream << language << "_FLAGS" << arch << " = " << flags + << "\n\n"; + } } } @@ -465,17 +492,37 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string configUpper = cmSystemTools::UpperCase(config); // Add precompile headers dependencies - const std::string pchSource = - this->GeneratorTarget->GetPchSource(config, lang); - if (!pchSource.empty() && !source.GetProperty("SKIP_PRECOMPILE_HEADERS")) { - std::string const& pchHeader = - this->GeneratorTarget->GetPchHeader(config, lang); - depends.push_back(pchHeader); - if (source.GetFullPath() != pchSource) { - depends.push_back(this->GeneratorTarget->GetPchFile(config, lang)); + std::vector<std::string> architectures; + this->GeneratorTarget->GetAppleArchs(config, architectures); + if (architectures.empty()) { + architectures.emplace_back(); + } + + std::string filterArch; + std::unordered_map<std::string, std::string> pchSources; + for (const std::string& arch : architectures) { + const std::string pchSource = + this->GeneratorTarget->GetPchSource(config, lang, arch); + if (pchSource == source.GetFullPath()) { + filterArch = arch; + } + if (!pchSource.empty()) { + pchSources.insert(std::make_pair(pchSource, arch)); + } + } + + if (!pchSources.empty() && !source.GetProperty("SKIP_PRECOMPILE_HEADERS")) { + for (const std::string& arch : architectures) { + std::string const& pchHeader = + this->GeneratorTarget->GetPchHeader(config, lang, arch); + depends.push_back(pchHeader); + if (pchSources.find(source.GetFullPath()) == pchSources.end()) { + depends.push_back( + this->GeneratorTarget->GetPchFile(config, lang, arch)); + } + this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang, + objFullPath, pchHeader); } - this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang, - objFullPath, pchHeader); } std::string relativeObj = @@ -486,7 +533,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string flags; // Add language-specific flags. - std::string langFlags = cmStrCat("$(", lang, "_FLAGS)"); + std::string langFlags = cmStrCat("$(", lang, "_FLAGS", filterArch, ")"); this->LocalGenerator->AppendFlags(flags, langFlags); cmGeneratorExpressionInterpreter genexInterpreter( @@ -495,13 +542,14 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // Add Fortran format flags. if (lang == "Fortran") { this->AppendFortranFormatFlags(flags, source); + this->AppendFortranPreprocessFlags(flags, source); } // Add flags from source file properties. const std::string COMPILE_FLAGS("COMPILE_FLAGS"); - if (const char* cflags = source.GetProperty(COMPILE_FLAGS)) { + if (cmProp cflags = source.GetProperty(COMPILE_FLAGS)) { const std::string& evaluatedFlags = - genexInterpreter.Evaluate(cflags, COMPILE_FLAGS); + genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS); this->LocalGenerator->AppendFlags(flags, evaluatedFlags); *this->FlagFileStream << "# Custom flags: " << relativeObj << "_FLAGS = " << evaluatedFlags << "\n" @@ -509,9 +557,9 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( } const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); - if (const char* coptions = source.GetProperty(COMPILE_OPTIONS)) { + if (cmProp coptions = source.GetProperty(COMPILE_OPTIONS)) { const std::string& evaluatedOptions = - genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS); + genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS); this->LocalGenerator->AppendCompileOptions(flags, evaluatedOptions); *this->FlagFileStream << "# Custom options: " << relativeObj << "_OPTIONS = " << evaluatedOptions << "\n" @@ -519,11 +567,12 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( } // Add precompile headers compile options. - if (!pchSource.empty() && !source.GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (!pchSources.empty() && !source.GetProperty("SKIP_PRECOMPILE_HEADERS")) { std::string pchOptions; - if (source.GetFullPath() == pchSource) { - pchOptions = - this->GeneratorTarget->GetPchCreateCompileOptions(config, lang); + auto pchIt = pchSources.find(source.GetFullPath()); + if (pchIt != pchSources.end()) { + pchOptions = this->GeneratorTarget->GetPchCreateCompileOptions( + config, lang, pchIt->second); } else { pchOptions = this->GeneratorTarget->GetPchUseCompileOptions(config, lang); @@ -542,9 +591,9 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::vector<std::string> includes; const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); - if (const char* cincludes = source.GetProperty(INCLUDE_DIRECTORIES)) { + if (cmProp cincludes = source.GetProperty(INCLUDE_DIRECTORIES)) { const std::string& evaluatedIncludes = - genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES); + genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES); this->LocalGenerator->AppendIncludeDirectories(includes, evaluatedIncludes, source); *this->FlagFileStream << "# Custom include directories: " << relativeObj @@ -558,18 +607,18 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // Add source-specific preprocessor definitions. const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); - if (const char* compile_defs = source.GetProperty(COMPILE_DEFINITIONS)) { + if (cmProp compile_defs = source.GetProperty(COMPILE_DEFINITIONS)) { const std::string& evaluatedDefs = - genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS); + genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS); this->LocalGenerator->AppendDefines(defines, evaluatedDefs); *this->FlagFileStream << "# Custom defines: " << relativeObj << "_DEFINES = " << evaluatedDefs << "\n" << "\n"; } std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper); - if (const char* config_compile_defs = source.GetProperty(defPropName)) { + if (cmProp config_compile_defs = source.GetProperty(defPropName)) { const std::string& evaluatedDefs = - genexInterpreter.Evaluate(config_compile_defs, COMPILE_DEFINITIONS); + genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS); this->LocalGenerator->AppendDefines(defines, evaluatedDefs); *this->FlagFileStream << "# Custom defines: " << relativeObj << "_DEFINES_" << configUpper << " = " << evaluatedDefs << "\n" @@ -639,7 +688,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GeneratorTarget->GetName().c_str(); vars.CMTargetType = - cmState::GetTargetTypeName(this->GeneratorTarget->GetType()); + cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str(); vars.Language = lang.c_str(); vars.Target = targetOutPathReal.c_str(); vars.TargetPDB = targetOutPathPDB.c_str(); @@ -717,8 +766,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // no launcher for CMAKE_EXPORT_COMPILE_COMMANDS rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, compileCommand, vars); - std::string workingDirectory = cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetCurrentBinaryDirectory()); + std::string workingDirectory = + this->LocalGenerator->GetCurrentBinaryDirectory(); compileCommand.replace(compileCommand.find(langFlags), langFlags.size(), this->GetFlags(lang, this->GetConfigName())); std::string langDefines = std::string("$(") + lang + "_DEFINES)"; @@ -750,25 +799,24 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" || lang == "OBJC" || lang == "OBJCXX")) { std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; - const char* clauncher = - this->GeneratorTarget->GetProperty(clauncher_prop); - if (clauncher && *clauncher) { - compilerLauncher = clauncher; + cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); + if (clauncher && !clauncher->empty()) { + compilerLauncher = *clauncher; } } // Maybe insert an include-what-you-use runner. if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) { std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; - const char* iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); + cmProp iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); std::string const tidy_prop = lang + "_CLANG_TIDY"; - const char* tidy = this->GeneratorTarget->GetProperty(tidy_prop); + cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop); std::string const cpplint_prop = lang + "_CPPLINT"; - const char* cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); + cmProp cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); std::string const cppcheck_prop = lang + "_CPPCHECK"; - const char* cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); - if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) || - (cppcheck && *cppcheck)) { + cmProp cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); + if ((iwyu && !iwyu->empty()) || (tidy && !tidy->empty()) || + (cpplint && !cpplint->empty()) || (cppcheck && !cppcheck->empty())) { std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_co_compile"; if (!compilerLauncher.empty()) { // In __run_co_compile case the launcher command is supplied @@ -777,11 +825,11 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher); compilerLauncher.clear(); } - if (iwyu && *iwyu) { + if (iwyu && !iwyu->empty()) { run_iwyu += " --iwyu="; - run_iwyu += this->LocalGenerator->EscapeForShell(iwyu); + run_iwyu += this->LocalGenerator->EscapeForShell(*iwyu); } - if (tidy && *tidy) { + if (tidy && !tidy->empty()) { run_iwyu += " --tidy="; const char* driverMode = this->Makefile->GetDefinition( "CMAKE_" + lang + "_CLANG_TIDY_DRIVER_MODE"); @@ -789,18 +837,18 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( driverMode = lang == "C" ? "gcc" : "g++"; } run_iwyu += this->LocalGenerator->EscapeForShell( - cmStrCat(tidy, ";--extra-arg-before=--driver-mode=", driverMode)); + cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode)); } - if (cpplint && *cpplint) { + if (cpplint && !cpplint->empty()) { run_iwyu += " --cpplint="; - run_iwyu += this->LocalGenerator->EscapeForShell(cpplint); + run_iwyu += this->LocalGenerator->EscapeForShell(*cpplint); } - if (cppcheck && *cppcheck) { + if (cppcheck && !cppcheck->empty()) { run_iwyu += " --cppcheck="; - run_iwyu += this->LocalGenerator->EscapeForShell(cppcheck); + run_iwyu += this->LocalGenerator->EscapeForShell(*cppcheck); } - if ((tidy && *tidy) || (cpplint && *cpplint) || - (cppcheck && *cppcheck)) { + if ((tidy && !tidy->empty()) || (cpplint && !cpplint->empty()) || + (cppcheck && !cppcheck->empty())) { run_iwyu += " --source="; run_iwyu += sourceFile; } @@ -848,10 +896,15 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // Check for extra outputs created by the compilation. std::vector<std::string> outputs(1, relativeObj); - if (const char* extra_outputs_str = source.GetProperty("OBJECT_OUTPUTS")) { - // Register these as extra files to clean. - cmExpandList(extra_outputs_str, outputs); - this->CleanFiles.insert(outputs.begin() + 1, outputs.end()); + if (cmProp extra_outputs_str = source.GetProperty("OBJECT_OUTPUTS")) { + std::string evaluated_outputs = cmGeneratorExpression::Evaluate( + *extra_outputs_str, this->LocalGenerator, config); + + if (!evaluated_outputs.empty()) { + // Register these as extra files to clean. + cmExpandList(evaluated_outputs, outputs); + this->CleanFiles.insert(outputs.begin() + 1, outputs.end()); + } } // Write the rule. @@ -1130,8 +1183,7 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() // translation table for the dependency scanning process. depCmd << "cd " << (this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetBinaryDirectory()), + this->LocalGenerator->GetBinaryDirectory(), cmOutputConverter::SHELL)) << " && "; #endif @@ -1147,23 +1199,19 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() depCmd << "$(CMAKE_COMMAND) -E cmake_depends \"" << this->GlobalGenerator->GetName() << "\" " << this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetSourceDirectory()), + this->LocalGenerator->GetSourceDirectory(), cmOutputConverter::SHELL) << " " << this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetCurrentSourceDirectory()), + this->LocalGenerator->GetCurrentSourceDirectory(), cmOutputConverter::SHELL) << " " << this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetBinaryDirectory()), + this->LocalGenerator->GetBinaryDirectory(), cmOutputConverter::SHELL) << " " << this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath( - this->LocalGenerator->GetCurrentBinaryDirectory()), + this->LocalGenerator->GetCurrentBinaryDirectory(), cmOutputConverter::SHELL) << " " << this->LocalGenerator->ConvertToOutputFormat( @@ -1206,8 +1254,8 @@ void cmMakefileTargetGenerator::WriteObjectDependRules( // Create the list of dependencies known at cmake time. These are // shared between the object file and dependency scanning rule. depends.push_back(source.GetFullPath()); - if (const char* objectDeps = source.GetProperty("OBJECT_DEPENDS")) { - cmExpandList(objectDeps, depends); + if (cmProp objectDeps = source.GetProperty("OBJECT_DEPENDS")) { + cmExpandList(*objectDeps, depends); } } @@ -1251,8 +1299,10 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile( // Setup implicit dependency scanning. for (auto const& idi : ccg.GetCC().GetImplicitDepends()) { - std::string objFullPath = cmSystemTools::CollapseFullPath(outputs[0]); - std::string srcFullPath = cmSystemTools::CollapseFullPath(idi.second); + std::string objFullPath = cmSystemTools::CollapseFullPath( + outputs[0], this->LocalGenerator->GetCurrentBinaryDirectory()); + std::string srcFullPath = cmSystemTools::CollapseFullPath( + idi.second, this->LocalGenerator->GetCurrentBinaryDirectory()); this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, idi.first, objFullPath, srcFullPath); } diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index ec6b31438..f38f86237 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -60,6 +60,8 @@ public: std::string GetConfigName(); protected: + void GetDeviceLinkFlags(std::string& linkFlags, + const std::string& linkLanguage); void GetTargetLinkFlags(std::string& flags, const std::string& linkLanguage); // create the file and directory etc diff --git a/Source/cmMathCommand.cxx b/Source/cmMathCommand.cxx index f11b906d4..56221bf5b 100644 --- a/Source/cmMathCommand.cxx +++ b/Source/cmMathCommand.cxx @@ -4,7 +4,7 @@ #include <cstdio> -#include "cm_kwiml.h" +#include <cm3p/kwiml/int.h> #include "cmExecutionStatus.h" #include "cmExprParserHelper.h" diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx index bf8183bbf..c7bb9a7a3 100644 --- a/Source/cmMessageCommand.cxx +++ b/Source/cmMessageCommand.cxx @@ -6,8 +6,7 @@ #include <utility> #include <cm/string_view> - -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmExecutionStatus.h" #include "cmMakefile.h" diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index ba2ea5b1c..b92548fd3 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -29,6 +29,7 @@ #include "cmNinjaTypes.h" #include "cmOSXBundleGenerator.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" #include "cmState.h" @@ -156,23 +157,25 @@ const char* cmNinjaNormalTargetGenerator::GetVisibleTypeName() const std::string cmNinjaNormalTargetGenerator::LanguageLinkerRule( const std::string& config) const { - return this->TargetLinkLanguage(config) + "_" + - cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) + - "_LINKER__" + + return cmStrCat( + this->TargetLinkLanguage(config), "_", + cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()), + "_LINKER__", cmGlobalNinjaGenerator::EncodeRuleName( - this->GetGeneratorTarget()->GetName()) + - "_" + config; + this->GetGeneratorTarget()->GetName()), + "_", config); } std::string cmNinjaNormalTargetGenerator::LanguageLinkerDeviceRule( const std::string& config) const { - return this->TargetLinkLanguage(config) + "_" + - cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) + - "_DEVICE_LINKER__" + + return cmStrCat( + this->TargetLinkLanguage(config), "_", + cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()), + "_DEVICE_LINKER__", cmGlobalNinjaGenerator::EncodeRuleName( - this->GetGeneratorTarget()->GetName()) + - "_" + config; + this->GetGeneratorTarget()->GetName()), + "_", config); } struct cmNinjaRemoveNoOpCommands @@ -191,7 +194,8 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule( cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); vars.CMTargetType = - cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()); + cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) + .c_str(); vars.Language = "CUDA"; @@ -230,11 +234,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule( vars.LinkFlags = "$LINK_FLAGS"; vars.Manifests = "$MANIFESTS"; - std::string langFlags; - if (this->GetGeneratorTarget()->GetType() != cmStateEnums::EXECUTABLE) { - langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS"; - vars.LanguageCompileFlags = langFlags.c_str(); - } + vars.LanguageCompileFlags = "$LANGUAGE_COMPILE_FLAGS"; std::string launcher; const char* val = this->GetLocalGenerator()->GetRuleLauncher( @@ -282,7 +282,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, cmNinjaRule rule(std::move(linkRuleName)); cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); - vars.CMTargetType = cmState::GetTargetTypeName(targetType); + vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str(); std::string lang = this->TargetLinkLanguage(config); vars.Language = config.c_str(); @@ -454,14 +454,12 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd() case cmStateEnums::STATIC_LIBRARY: case cmStateEnums::SHARED_LIBRARY: case cmStateEnums::MODULE_LIBRARY: { - const std::string cudaLinkCmd( - this->GetMakefile()->GetDefinition("CMAKE_CUDA_DEVICE_LINK_LIBRARY")); - cmExpandList(cudaLinkCmd, linkCmds); + this->GetMakefile()->GetDefExpandList("CMAKE_CUDA_DEVICE_LINK_LIBRARY", + linkCmds); } break; case cmStateEnums::EXECUTABLE: { - const std::string cudaLinkCmd(this->GetMakefile()->GetDefinition( - "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE")); - cmExpandList(cudaLinkCmd, linkCmds); + this->GetMakefile()->GetDefExpandList( + "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE", linkCmds); } break; default: break; @@ -558,9 +556,8 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd( 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); + this->Makefile->GetDefExpandList("CMAKE_EXE_EXPORTS_Swift_FLAG", + linkCmds); } } break; @@ -587,8 +584,6 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement( return; } - // Now we can do device linking - // First and very important step is to make sure while inside this // step our link language is set to CUDA std::string cudaLinkLanguage = "CUDA"; @@ -674,9 +669,9 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement( linkLineComputer->SetUseWatcomQuote(useWatcomQuote); linkLineComputer->SetUseNinjaMulti(globalGen->IsMultiConfig()); - localGen.GetTargetFlags( - linkLineComputer.get(), config, vars["LINK_LIBRARIES"], vars["FLAGS"], - vars["LINK_FLAGS"], frameworkPath, linkPath, genTarget); + localGen.GetDeviceLinkFlags(linkLineComputer.get(), config, + vars["LINK_LIBRARIES"], vars["LINK_FLAGS"], + frameworkPath, linkPath, genTarget); this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars); @@ -686,22 +681,12 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement( vars["LINK_PATH"] = frameworkPath + linkPath; - // Compute architecture specific link flags. Yes, these go into a different - // variable for executables, probably due to a mistake made when duplicating - // code between the Makefile executable and library generators. - if (targetType == cmStateEnums::EXECUTABLE) { - std::string t = vars["FLAGS"]; - localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, config); - vars["FLAGS"] = t; - } else { - std::string t = vars["ARCH_FLAGS"]; - localGen.AddArchitectureFlags(t, genTarget, cudaLinkLanguage, config); - vars["ARCH_FLAGS"] = t; - t.clear(); - localGen.AddLanguageFlagsForLinking(t, genTarget, cudaLinkLanguage, - config); - vars["LANGUAGE_COMPILE_FLAGS"] = t; - } + // Compute language specific link flags. + std::string langFlags; + localGen.AddLanguageFlagsForLinking(langFlags, genTarget, cudaLinkLanguage, + config); + vars["LANGUAGE_COMPILE_FLAGS"] = langFlags; + auto const tgtNames = this->TargetNames(config); if (genTarget->HasSOName(config)) { vars["SONAME_FLAG"] = @@ -748,9 +733,8 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement( static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) - globalGen->GetRuleCmdLength(this->LanguageLinkerDeviceRule(config)); - build.RspFile = this->ConvertToNinjaPath( - cmStrCat("CMakeFiles/", genTarget->GetName(), - globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp")); + build.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") + + genTarget->GetName() + ".rsp"); // Gather order-only dependencies. this->GetLocalGenerator()->AppendTargetDepends( @@ -813,8 +797,20 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( targetOutputReal = this->ConvertToNinjaPath(targetOutputReal); } else if (gt->IsFrameworkOnApple()) { // Create the library framework. + + 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); + tgtNames.Output, gt->GetDirectory(config), config, bundleSkipParts); } else if (gt->IsCFBundleOnApple()) { // Create the core foundation bundle. this->OSXBundleGenerator->CreateCFBundle(tgtNames.Output, @@ -849,8 +845,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( }(); vars["SWIFT_MODULE_NAME"] = [gt]() -> std::string { - if (const char* name = gt->GetProperty("Swift_MODULE_NAME")) { - return name; + if (cmProp name = gt->GetProperty("Swift_MODULE_NAME")) { + return *name; } return gt->GetName(); }(); @@ -858,15 +854,15 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( vars["SWIFT_MODULE"] = [this](const std::string& module) -> std::string { std::string directory = this->GetLocalGenerator()->GetCurrentBinaryDirectory(); - if (const char* prop = this->GetGeneratorTarget()->GetProperty( + if (cmProp prop = this->GetGeneratorTarget()->GetProperty( "Swift_MODULE_DIRECTORY")) { - directory = prop; + directory = *prop; } std::string name = module + ".swiftmodule"; - if (const char* prop = + if (cmProp prop = this->GetGeneratorTarget()->GetProperty("Swift_MODULE")) { - name = prop; + name = *prop; } return this->GetLocalGenerator()->ConvertToOutputFormat( @@ -1026,11 +1022,11 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( std::string prefix; std::string base; std::string suffix; - gt->GetFullNameComponents(prefix, base, suffix); + gt->GetFullNameComponents(prefix, base, suffix, config); std::string dbg_suffix = ".dbg"; // TODO: Where to document? - if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) { - dbg_suffix = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX"); + if (auto d = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) { + dbg_suffix = d; } vars["TARGET_PDB"] = base + suffix + dbg_suffix; } @@ -1158,9 +1154,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( globalGen->GetRuleCmdLength(linkBuild.Rule); } - linkBuild.RspFile = this->ConvertToNinjaPath( - cmStrCat("CMakeFiles/", gt->GetName(), - globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp")); + linkBuild.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") + + gt->GetName() + ".rsp"); // Gather order-only dependencies. this->GetLocalGenerator()->AppendTargetDepends(gt, linkBuild.OrderOnlyDeps, diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 486ed8d33..d406c9951 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -7,13 +7,15 @@ #include <iterator> #include <map> #include <ostream> +#include <unordered_map> +#include <unordered_set> #include <utility> #include <cm/memory> #include <cmext/algorithm> -#include "cm_jsoncpp_value.h" -#include "cm_jsoncpp_writer.h" +#include <cm3p/json/value.h> +#include <cm3p/json/writer.h> #include "cmComputeLinkInformation.h" #include "cmCustomCommandGenerator.h" @@ -27,6 +29,7 @@ #include "cmNinjaNormalTargetGenerator.h" #include "cmNinjaUtilityTargetGenerator.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" @@ -94,17 +97,28 @@ cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const std::string cmNinjaTargetGenerator::LanguageCompilerRule( const std::string& lang, const std::string& config) const { - return lang + "_COMPILER__" + - cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()) + - "_" + config; + return cmStrCat( + lang, "_COMPILER__", + cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), + '_', config); } std::string cmNinjaTargetGenerator::LanguagePreprocessRule( std::string const& lang, const std::string& config) const { - return lang + "_PREPROCESS__" + - cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()) + - "_" + config; + return cmStrCat( + lang, "_PREPROCESS_SCAN__", + cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), + '_', config); +} + +std::string cmNinjaTargetGenerator::LanguageDependencyRule( + std::string const& lang, const std::string& config) const +{ + return cmStrCat( + lang, "_SCAN__", + cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), + '_', config); } bool cmNinjaTargetGenerator::NeedExplicitPreprocessing( @@ -129,9 +143,10 @@ bool cmNinjaTargetGenerator::CompilePreprocessedSourceWithDefines( std::string cmNinjaTargetGenerator::LanguageDyndepRule( const std::string& lang, const std::string& config) const { - return lang + "_DYNDEP__" + - cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()) + - "_" + config; + return cmStrCat( + lang, "_DYNDEP__", + cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), + '_', config); } bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const @@ -154,11 +169,31 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( cmSourceFile const* source, const std::string& language, const std::string& config) { - std::string flags = this->GetFlags(language, config); + std::vector<std::string> architectures; + std::unordered_map<std::string, std::string> pchSources; + this->GeneratorTarget->GetAppleArchs(config, architectures); + if (architectures.empty()) { + architectures.emplace_back(); + } + + std::string filterArch; + for (const std::string& arch : architectures) { + const std::string pchSource = + this->GeneratorTarget->GetPchSource(config, language, arch); + if (pchSource == source->GetFullPath()) { + filterArch = arch; + } + if (!pchSource.empty()) { + pchSources.insert(std::make_pair(pchSource, arch)); + } + } + + std::string flags = this->GetFlags(language, config, filterArch); // Add Fortran format flags. if (language == "Fortran") { this->AppendFortranFormatFlags(flags, *source); + this->AppendFortranPreprocessFlags(flags, *source); } // Add source file specific flags. @@ -166,26 +201,24 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( this->LocalGenerator, config, this->GeneratorTarget, language); const std::string COMPILE_FLAGS("COMPILE_FLAGS"); - if (const char* cflags = source->GetProperty(COMPILE_FLAGS)) { + if (cmProp cflags = source->GetProperty(COMPILE_FLAGS)) { this->LocalGenerator->AppendFlags( - flags, genexInterpreter.Evaluate(cflags, COMPILE_FLAGS)); + flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS)); } const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); - if (const char* coptions = source->GetProperty(COMPILE_OPTIONS)) { + if (cmProp coptions = source->GetProperty(COMPILE_OPTIONS)) { this->LocalGenerator->AppendCompileOptions( - flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); + flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS)); } // Add precompile headers compile options. - const std::string pchSource = - this->GeneratorTarget->GetPchSource(config, language); - - if (!pchSource.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { std::string pchOptions; - if (source->GetFullPath() == pchSource) { - pchOptions = - this->GeneratorTarget->GetPchCreateCompileOptions(config, language); + auto pchIt = pchSources.find(source->GetFullPath()); + if (pchIt != pchSources.end()) { + pchOptions = this->GeneratorTarget->GetPchCreateCompileOptions( + config, language, pchIt->second); } else { pchOptions = this->GeneratorTarget->GetPchUseCompileOptions(config, language); @@ -219,8 +252,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; } @@ -259,17 +292,17 @@ std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source, } const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); - if (const char* compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) { + if (cmProp compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) { this->LocalGenerator->AppendDefines( - defines, genexInterpreter.Evaluate(compile_defs, COMPILE_DEFINITIONS)); + defines, genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS)); } std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config)); - if (const char* config_compile_defs = source->GetProperty(defPropName)) { + if (cmProp config_compile_defs = source->GetProperty(defPropName)) { this->LocalGenerator->AppendDefines( defines, - genexInterpreter.Evaluate(config_compile_defs, COMPILE_DEFINITIONS)); + genexInterpreter.Evaluate(*config_compile_defs, COMPILE_DEFINITIONS)); } std::string definesString = this->GetDefines(language, config); @@ -287,9 +320,9 @@ std::string cmNinjaTargetGenerator::ComputeIncludes( this->LocalGenerator, config, this->GeneratorTarget, language); const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); - if (const char* cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) { + if (cmProp cincludes = source->GetProperty(INCLUDE_DIRECTORIES)) { this->LocalGenerator->AppendIncludeDirectories( - includes, genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES), + includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES), *source); } @@ -355,13 +388,12 @@ std::string cmNinjaTargetGenerator::GetObjectFilePath( { 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 += this->GetGlobalGenerator()->ConfigDirectory(config); - path += "/"; - path += objectName; + path += cmStrCat( + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), + this->GetGlobalGenerator()->ConfigDirectory(config), '/', objectName); return path; } @@ -389,16 +421,15 @@ 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 += this->GetGlobalGenerator()->ConfigDirectory(config); - path += "/"; - path += ppName; + path += + cmStrCat(this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), + this->GetGlobalGenerator()->ConfigDirectory(config), '/', ppName); return path; } @@ -407,13 +438,11 @@ std::string cmNinjaTargetGenerator::GetDyndepFilePath( { std::string path = this->LocalGenerator->GetHomeRelativeOutputPath(); if (!path.empty()) { - path += "/"; + path += '/'; } - path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); - path += this->GetGlobalGenerator()->ConfigDirectory(config); - path += "/"; - path += lang; - path += ".dd"; + path += cmStrCat( + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), + this->GetGlobalGenerator()->ConfigDirectory(config), '/', lang, ".dd"); return path; } @@ -442,8 +471,7 @@ std::string cmNinjaTargetGenerator::GetTargetFilePath( if (path.empty() || path == ".") { return name; } - path += "/"; - path += name; + path += cmStrCat('/', name); return path; } @@ -491,13 +519,98 @@ void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language, this->WriteCompileRule(language, config); } +namespace { +// Create the command to run the dependency scanner +std::string GetScanCommand(const std::string& cmakeCmd, const std::string& tdi, + const std::string& lang, const std::string& ppFile, + bool needDyndep, const std::string& ddiFile) +{ + std::string ccmd = + cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi, " --lang=", lang, + " --pp=", ppFile, " --dep=$DEP_FILE"); + if (needDyndep) { + ccmd = cmStrCat(ccmd, " --obj=$OBJ_FILE --ddi=", ddiFile); + } + return ccmd; +} + +// Helper function to create dependency scanning rule, with optional +// explicit preprocessing step if preprocessCommand is non-empty +cmNinjaRule GetPreprocessScanRule( + const std::string& ruleName, cmRulePlaceholderExpander::RuleVariables& vars, + const std::string& responseFlag, const std::string& flags, + const std::string& launcher, + cmRulePlaceholderExpander* const rulePlaceholderExpander, + std::string scanCommand, cmLocalNinjaGenerator* generator, + const std::string& preprocessCommand = "") +{ + cmNinjaRule rule(ruleName); + // Explicit preprocessing always uses a depfile. + rule.DepType = ""; // no deps= for multiple outputs + rule.DepFile = "$DEP_FILE"; + + cmRulePlaceholderExpander::RuleVariables ppVars; + ppVars.CMTargetName = vars.CMTargetName; + ppVars.CMTargetType = vars.CMTargetType; + ppVars.Language = vars.Language; + ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE + ppVars.PreprocessedSource = "$out"; + ppVars.DependencyFile = rule.DepFile.c_str(); + + // Preprocessing uses the original source, compilation uses + // preprocessed output or original source + ppVars.Source = vars.Source; + vars.Source = "$in"; + + // Copy preprocessor definitions to the preprocessor rule. + ppVars.Defines = vars.Defines; + + // Copy include directories to the preprocessor rule. The Fortran + // compilation rule still needs them for the INCLUDE directive. + ppVars.Includes = vars.Includes; + + // Preprocessing and compilation use the same flags. + std::string ppFlags = flags; + + // If using a response file, move defines, includes, and flags into it. + if (!responseFlag.empty()) { + rule.RspFile = "$RSP_FILE"; + rule.RspContent = + cmStrCat(' ', ppVars.Defines, ' ', ppVars.Includes, ' ', ppFlags); + ppFlags = cmStrCat(responseFlag, rule.RspFile); + ppVars.Defines = ""; + ppVars.Includes = ""; + } + + ppVars.Flags = ppFlags.c_str(); + + // Rule for preprocessing source file. + std::vector<std::string> ppCmds; + + if (!preprocessCommand.empty()) { + // Lookup the explicit preprocessing rule. + cmExpandList(preprocessCommand, ppCmds); + for (std::string& i : ppCmds) { + i = cmStrCat(launcher, i); + rulePlaceholderExpander->ExpandRuleVariables(generator, i, ppVars); + } + } + + // Run CMake dependency scanner on either preprocessed output or source file + ppCmds.emplace_back(std::move(scanCommand)); + rule.Command = generator->BuildCommandLine(ppCmds); + + return rule; +} +} + void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, const std::string& config) { cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); vars.CMTargetType = - cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()); + cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str(); vars.Language = lang.c_str(); vars.Source = "$in"; vars.Object = "$out"; @@ -522,7 +635,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 = "@"; @@ -548,82 +661,42 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); if (explicitPP) { - cmNinjaRule rule(this->LanguagePreprocessRule(lang, config)); - // Explicit preprocessing always uses a depfile. - rule.DepType = ""; // no deps= for multiple outputs - rule.DepFile = "$DEP_FILE"; + // Combined preprocessing and dependency scanning + const auto ppScanCommand = GetScanCommand( + cmakeCmd, tdi, lang, "$out", needDyndep, "$DYNDEP_INTERMEDIATE_FILE"); + const auto ppVar = cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE"); - cmRulePlaceholderExpander::RuleVariables ppVars; - ppVars.CMTargetName = vars.CMTargetName; - ppVars.CMTargetType = vars.CMTargetType; - ppVars.Language = vars.Language; - ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE - ppVars.PreprocessedSource = "$out"; - ppVars.DependencyFile = rule.DepFile.c_str(); + auto ppRule = GetPreprocessScanRule( + this->LanguagePreprocessRule(lang, config), vars, responseFlag, flags, + launcher, rulePlaceholderExpander.get(), ppScanCommand, + this->GetLocalGenerator(), mf->GetRequiredDefinition(ppVar)); - // Preprocessing uses the original source, - // compilation uses preprocessed output. - ppVars.Source = vars.Source; - vars.Source = "$in"; + // Write the rule for preprocessing file of the given language. + ppRule.Comment = cmStrCat("Rule for preprocessing ", lang, " files."); + ppRule.Description = cmStrCat("Building ", lang, " preprocessed $out"); - // Preprocessing and compilation use the same flags. - std::string ppFlags = flags; + this->GetGlobalGenerator()->AddRule(ppRule); if (!compilePPWithDefines) { - // Move preprocessor definitions to the preprocessor rule. - ppVars.Defines = vars.Defines; + // Remove preprocessor definitions from compilation step vars.Defines = ""; - } else { - // Copy preprocessor definitions to the preprocessor rule. - ppVars.Defines = vars.Defines; } - // Copy include directories to the preprocessor rule. The Fortran - // compilation rule still needs them for the INCLUDE directive. - ppVars.Includes = vars.Includes; - - // If using a response file, move defines, includes, and flags into it. - if (!responseFlag.empty()) { - rule.RspFile = "$RSP_FILE"; - rule.RspContent = - cmStrCat(' ', ppVars.Defines, ' ', ppVars.Includes, ' ', ppFlags); - ppFlags = responseFlag + rule.RspFile; - ppVars.Defines = ""; - ppVars.Includes = ""; - } + // Just dependency scanning for files that have preprocessing turned off + const auto scanCommand = + GetScanCommand(cmakeCmd, tdi, lang, "$in", needDyndep, "$out"); - ppVars.Flags = ppFlags.c_str(); + auto scanRule = GetPreprocessScanRule( + this->LanguageDependencyRule(lang, config), vars, "", flags, launcher, + rulePlaceholderExpander.get(), scanCommand, this->GetLocalGenerator()); - // Rule for preprocessing source file. - std::vector<std::string> ppCmds; - { - // Lookup the explicit preprocessing rule. - std::string ppVar = cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE"); - cmExpandList(this->GetMakefile()->GetRequiredDefinition(ppVar), ppCmds); - } + // Write the rule for generating dependencies for the given language. + scanRule.Comment = cmStrCat("Rule for generating ", lang, + " dependencies on non-preprocessed files."); + scanRule.Description = + cmStrCat("Generating ", lang, " dependencies for $in"); - for (std::string& i : ppCmds) { - i = cmStrCat(launcher, i); - rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), - i, ppVars); - } - - // Run CMake dependency scanner on preprocessed output. - { - std::string ccmd = - cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi, - " --lang=", lang, " --pp=$out --dep=$DEP_FILE"); - if (needDyndep) { - ccmd += " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE"; - } - ppCmds.emplace_back(std::move(ccmd)); - } - rule.Command = this->GetLocalGenerator()->BuildCommandLine(ppCmds); - - // Write the rule for preprocessing file of the given language. - rule.Comment = cmStrCat("Rule for preprocessing ", lang, " files."); - rule.Description = cmStrCat("Building ", lang, " preprocessed $out"); - this->GetGlobalGenerator()->AddRule(rule); + this->GetGlobalGenerator()->AddRule(scanRule); } if (needDyndep) { @@ -658,7 +731,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, 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 = ""; } @@ -671,15 +744,15 @@ 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()) { rule.DepType = "gcc"; rule.DepFile = "$DEP_FILE"; - const std::string cl = mf->GetDefinition("CMAKE_C_COMPILER") - ? mf->GetSafeDefinition("CMAKE_C_COMPILER") - : mf->GetSafeDefinition("CMAKE_CXX_COMPILER"); + auto d = mf->GetDefinition("CMAKE_C_COMPILER"); + const std::string cl = + d ? d : mf->GetSafeDefinition("CMAKE_CXX_COMPILER"); cldeps = cmStrCat('"', cmSystemTools::GetCMClDepsCommand(), "\" ", lang, ' ', vars.Source, " $DEP_FILE $out \"", mf->GetSafeDefinition("CMAKE_CL_SHOWINCLUDES_PREFIX"), @@ -688,14 +761,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); } } @@ -718,7 +791,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); } @@ -728,57 +801,59 @@ 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"; - const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); - if (clauncher && *clauncher) { - compilerLauncher = clauncher; + std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER"); + cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); + if (clauncher && !clauncher->empty()) { + compilerLauncher = *clauncher; } } // 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"; - const char* iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); - std::string const tidy_prop = lang + "_CLANG_TIDY"; - const char* tidy = this->GeneratorTarget->GetProperty(tidy_prop); - std::string const cpplint_prop = lang + "_CPPLINT"; - const char* cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); - std::string const cppcheck_prop = lang + "_CPPCHECK"; - const char* cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); - if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) || - (cppcheck && *cppcheck)) { + std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE"); + cmProp iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); + std::string const tidy_prop = cmStrCat(lang, "_CLANG_TIDY"); + cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop); + std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT"); + cmProp cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); + std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK"); + cmProp cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); + if ((iwyu && !iwyu->empty()) || (tidy && !tidy->empty()) || + (cpplint && !cpplint->empty()) || (cppcheck && !cppcheck->empty())) { std::string run_iwyu = cmStrCat(cmakeCmd, " -E __run_co_compile"); 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); + if (iwyu && !iwyu->empty()) { + run_iwyu += cmStrCat(" --iwyu=", + this->GetLocalGenerator()->EscapeForShell(*iwyu)); } - if (tidy && *tidy) { + if (tidy && !tidy->empty()) { run_iwyu += " --tidy="; const char* driverMode = this->Makefile->GetDefinition( - "CMAKE_" + lang + "_CLANG_TIDY_DRIVER_MODE"); + 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)); + cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode)); } - if (cpplint && *cpplint) { - run_iwyu += " --cpplint="; - run_iwyu += this->GetLocalGenerator()->EscapeForShell(cpplint); + if (cpplint && !cpplint->empty()) { + run_iwyu += cmStrCat( + " --cpplint=", this->GetLocalGenerator()->EscapeForShell(*cpplint)); } - if (cppcheck && *cppcheck) { - run_iwyu += " --cppcheck="; - run_iwyu += this->GetLocalGenerator()->EscapeForShell(cppcheck); + if (cppcheck && !cppcheck->empty()) { + run_iwyu += + cmStrCat(" --cppcheck=", + this->GetLocalGenerator()->EscapeForShell(*cppcheck)); } - if ((tidy && *tidy) || (cpplint && *cpplint) || - (cppcheck && *cppcheck)) { + if ((tidy && !tidy->empty()) || (cpplint && !cpplint->empty()) || + (cppcheck && !cppcheck->empty())) { run_iwyu += " --source=$in"; } run_iwyu += " -- "; @@ -797,7 +872,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()) { @@ -872,7 +947,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( { cmNinjaBuild build("phony"); - build.Comment = "Order-only phony target for " + this->GetTargetName(); + build.Comment = + cmStrCat("Order-only phony target for ", this->GetTargetName()); build.Outputs.push_back(this->OrderDependsTargetForTarget(config)); cmNinjaDeps& orderOnlyDeps = build.OrderOnlyDeps; @@ -957,12 +1033,12 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( "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; + if (cmProp name = target->GetProperty("Swift_DEPENDENCIES_FILE")) { + return *name; } - return this->ConvertToNinjaPath(target->GetSupportDirectory() + "/" + - config + "/" + target->GetName() + - ".swiftdeps"); + return this->ConvertToNinjaPath( + cmStrCat(target->GetSupportDirectory(), '/', config, '/', + target->GetName(), ".swiftdeps")); }(); // build the global target dependencies @@ -976,6 +1052,82 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( } } +namespace { +cmNinjaBuild GetPreprocessOrScanBuild( + const std::string& ruleName, const std::string& ppFileName, bool compilePP, + bool compilePPWithDefines, cmNinjaBuild& objBuild, cmNinjaVars& vars, + const std::string& depFileName, bool needDyndep, + const std::string& objectFileName) +{ + // Explicit preprocessing and dependency + cmNinjaBuild ppBuild(ruleName); + + if (!ppFileName.empty()) { + ppBuild.Outputs.push_back(ppFileName); + ppBuild.RspFile = cmStrCat(ppFileName, ".rsp"); + } else { + ppBuild.RspFile = "$out.rsp"; + } + + if (compilePP) { + // Move compilation dependencies to the preprocessing build statement. + std::swap(ppBuild.ExplicitDeps, objBuild.ExplicitDeps); + std::swap(ppBuild.ImplicitDeps, objBuild.ImplicitDeps); + std::swap(ppBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps); + std::swap(ppBuild.Variables["IN_ABS"], vars["IN_ABS"]); + + // The actual compilation will now use the preprocessed source. + objBuild.ExplicitDeps.push_back(ppFileName); + } else { + // Copy compilation dependencies to the preprocessing build statement. + ppBuild.ExplicitDeps = objBuild.ExplicitDeps; + ppBuild.ImplicitDeps = objBuild.ImplicitDeps; + ppBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps; + ppBuild.Variables["IN_ABS"] = vars["IN_ABS"]; + } + + // Preprocessing and compilation generally use the same flags. + ppBuild.Variables["FLAGS"] = vars["FLAGS"]; + + if (compilePP && !compilePPWithDefines) { + // Move preprocessor definitions to the preprocessor build statement. + std::swap(ppBuild.Variables["DEFINES"], vars["DEFINES"]); + } else { + // Copy preprocessor definitions to the preprocessor build statement. + ppBuild.Variables["DEFINES"] = vars["DEFINES"]; + } + + // Copy include directories to the preprocessor build statement. The + // Fortran compilation build statement still needs them for the INCLUDE + // directive. + ppBuild.Variables["INCLUDES"] = vars["INCLUDES"]; + + // Explicit preprocessing always uses a depfile. + ppBuild.Variables["DEP_FILE"] = depFileName; + if (compilePP) { + // The actual compilation does not need a depfile because it + // depends on the already-preprocessed source. + vars.erase("DEP_FILE"); + } + + if (needDyndep) { + // Tell dependency scanner the object file that will result from + // compiling the source. + ppBuild.Variables["OBJ_FILE"] = objectFileName; + + // Tell dependency scanner where to store dyndep intermediate results. + std::string const ddiFile = cmStrCat(objectFileName, ".ddi"); + if (ppFileName.empty()) { + ppBuild.Outputs.push_back(ddiFile); + } else { + ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile; + ppBuild.ImplicitOuts.push_back(ddiFile); + } + } + return ppBuild; +} +} + void cmNinjaTargetGenerator::WriteObjectBuildStatement( cmSourceFile const* source, const std::string& config, const std::string& fileConfig, bool firstForConfig) @@ -994,7 +1146,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( 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); @@ -1019,14 +1171,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); } } @@ -1049,17 +1202,35 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // Add precompile headers dependencies std::vector<std::string> depList; - const std::string pchSource = - this->GeneratorTarget->GetPchSource(config, language); - if (!pchSource.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { - depList.push_back(this->GeneratorTarget->GetPchHeader(config, language)); - if (source->GetFullPath() != pchSource) { - depList.push_back(this->GeneratorTarget->GetPchFile(config, language)); + std::vector<std::string> architectures; + this->GeneratorTarget->GetAppleArchs(config, architectures); + if (architectures.empty()) { + architectures.emplace_back(); + } + + std::unordered_set<std::string> pchSources; + for (const std::string& arch : architectures) { + const std::string pchSource = + this->GeneratorTarget->GetPchSource(config, language, arch); + + if (!pchSource.empty()) { + pchSources.insert(pchSource); + } + } + + if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { + for (const std::string& arch : architectures) { + depList.push_back( + this->GeneratorTarget->GetPchHeader(config, language, arch)); + if (pchSources.find(source->GetFullPath()) == pchSources.end()) { + depList.push_back( + this->GeneratorTarget->GetPchFile(config, language, arch)); + } } } - if (const char* objectDeps = source->GetProperty("OBJECT_DEPENDS")) { - std::vector<std::string> objDepList = cmExpandedList(objectDeps); + if (cmProp objectDeps = source->GetProperty("OBJECT_DEPENDS")) { + std::vector<std::string> objDepList = cmExpandedList(*objectDeps); std::copy(objDepList.begin(), objDepList.end(), std::back_inserter(depList)); } @@ -1095,59 +1266,47 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // For some cases we do an explicit preprocessor invocation. bool const explicitPP = this->NeedExplicitPreprocessing(language); if (explicitPP) { - cmNinjaBuild ppBuild(this->LanguagePreprocessRule(language, config)); - std::string const ppFileName = - this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source, config)); - ppBuild.Outputs.push_back(ppFileName); - - ppBuild.RspFile = ppFileName + ".rsp"; + // If source/target has preprocessing turned off, we still need to + // generate an explicit dependency step + const auto srcpp = source->GetSafeProperty("Fortran_PREPROCESS"); + cmOutputConverter::FortranPreprocess preprocess = + cmOutputConverter::GetFortranPreprocess(srcpp); + if (preprocess == cmOutputConverter::FortranPreprocess::Unset) { + const auto& tgtpp = + this->GeneratorTarget->GetSafeProperty("Fortran_PREPROCESS"); + preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp); + } - bool const compilePP = this->UsePreprocessedSource(language); + bool const compilePP = this->UsePreprocessedSource(language) && + (preprocess != cmOutputConverter::FortranPreprocess::NotNeeded); bool const compilePPWithDefines = compilePP && this->CompilePreprocessedSourceWithDefines(language); - if (compilePP) { - // Move compilation dependencies to the preprocessing build statement. - std::swap(ppBuild.ExplicitDeps, objBuild.ExplicitDeps); - std::swap(ppBuild.ImplicitDeps, objBuild.ImplicitDeps); - std::swap(ppBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps); - std::swap(ppBuild.Variables["IN_ABS"], vars["IN_ABS"]); - - // The actual compilation will now use the preprocessed source. - objBuild.ExplicitDeps.push_back(ppFileName); - } else { - // Copy compilation dependencies to the preprocessing build statement. - ppBuild.ExplicitDeps = objBuild.ExplicitDeps; - ppBuild.ImplicitDeps = objBuild.ImplicitDeps; - ppBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps; - ppBuild.Variables["IN_ABS"] = vars["IN_ABS"]; - } - // Preprocessing and compilation generally use the same flags. - ppBuild.Variables["FLAGS"] = vars["FLAGS"]; + std::string const ppFileName = compilePP + ? this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source, config)) + : ""; + + std::string const buildName = compilePP + ? this->LanguagePreprocessRule(language, config) + : this->LanguageDependencyRule(language, config); + + const auto depExtension = compilePP ? ".pp.d" : ".d"; + const std::string depFileName = + this->GetLocalGenerator()->ConvertToOutputFormat( + cmStrCat(objectFileName, depExtension), cmOutputConverter::SHELL); + + cmNinjaBuild ppBuild = GetPreprocessOrScanBuild( + buildName, ppFileName, compilePP, compilePPWithDefines, objBuild, vars, + depFileName, needDyndep, objectFileName); if (compilePP) { // In case compilation requires flags that are incompatible with // 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); - } - - if (compilePP && !compilePPWithDefines) { - // Move preprocessor definitions to the preprocessor build statement. - std::swap(ppBuild.Variables["DEFINES"], vars["DEFINES"]); - } else { - // Copy preprocessor definitions to the preprocessor build statement. - ppBuild.Variables["DEFINES"] = vars["DEFINES"]; - } - - // Copy include directories to the preprocessor build statement. The - // Fortran compilation build statement still needs them for the INCLUDE - // directive. - ppBuild.Variables["INCLUDES"] = vars["INCLUDES"]; - if (compilePP) { // Prepend source file's original directory as an include directory // so e.g. Fortran INCLUDE statements can look for files in it. std::vector<std::string> sourceDirectory; @@ -1158,31 +1317,12 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( sourceDirectory, this->GeneratorTarget, language, false, false, 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); - if (compilePP) { - // The actual compilation does not need a depfile because it - // depends on the already-preprocessed source. - vars.erase("DEP_FILE"); - } - - if (needDyndep) { - // Tell dependency scanner the object file that will result from - // compiling the source. - ppBuild.Variables["OBJ_FILE"] = objectFileName; - - // Tell dependency scanner where to store dyndep intermediate results. - std::string const ddiFile = objectFileName + ".ddi"; - ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile; - ppBuild.ImplicitOuts.push_back(ddiFile); - if (firstForConfig) { - this->Configs[config].DDIFiles[language].push_back(ddiFile); - } + if (firstForConfig && needDyndep) { + std::string const ddiFile = cmStrCat(objectFileName, ".ddi"); + this->Configs[config].DDIFiles[language].push_back(ddiFile); } this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(), @@ -1207,8 +1347,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(), vars); - if (!pchSource.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { - if (source->GetFullPath() == pchSource) { + if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { + auto pchIt = pchSources.find(source->GetFullPath()); + if (pchIt != pchSources.end()) { this->addPoolNinjaVariable("JOB_POOL_PRECOMPILE_HEADER", this->GetGeneratorTarget(), vars); } @@ -1216,7 +1357,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( this->SetMsvcTargetPdbVariable(vars, config); - objBuild.RspFile = objectFileName + ".rsp"; + objBuild.RspFile = cmStrCat(objectFileName, ".rsp"); if (language == "Swift") { this->EmitSwiftDependencyInfo(source, config); @@ -1225,15 +1366,20 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( objBuild, commandLineLengthLimit); } - if (const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) { - cmNinjaBuild build("phony"); - build.Comment = "Additional output files."; - build.Outputs = cmExpandedList(objectOutputs); - std::transform(build.Outputs.begin(), build.Outputs.end(), - build.Outputs.begin(), MapToNinjaPath()); - build.ExplicitDeps = objBuild.Outputs; - this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), - build); + if (cmProp objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) { + std::string evaluatedObjectOutputs = cmGeneratorExpression::Evaluate( + *objectOutputs, this->LocalGenerator, config); + + if (!evaluatedObjectOutputs.empty()) { + cmNinjaBuild build("phony"); + build.Comment = "Additional output files."; + build.Outputs = cmExpandedList(evaluatedObjectOutputs); + std::transform(build.Outputs.begin(), build.Outputs.end(), + build.Outputs.begin(), MapToNinjaPath()); + build.ExplicitDeps = objBuild.Outputs; + this->GetGlobalGenerator()->WriteBuild( + this->GetImplFileStream(fileConfig), build); + } } } @@ -1242,8 +1388,8 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang, { 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( @@ -1292,16 +1438,16 @@ void cmNinjaTargetGenerator::EmitSwiftDependencyInfo( std::string const objectFilePath = 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; + if (cmProp 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; + if (cmProp name = source->GetProperty("Swift_DIAGNOSTICS_FILE")) { + return *name; } - return objectFilePath + ".dia"; + return cmStrCat(objectFilePath, ".dia"); }(); std::string const makeDepsPath = [this, source, config]() -> std::string { cmLocalNinjaGenerator const* local = this->GetLocalGenerator(); @@ -1311,12 +1457,13 @@ void cmNinjaTargetGenerator::EmitSwiftDependencyInfo( 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); }(); @@ -1381,7 +1528,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); @@ -1404,11 +1551,11 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( void cmNinjaTargetGenerator::AdditionalCleanFiles(const std::string& config) { - if (const char* prop_value = + if (cmProp prop_value = this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) { cmLocalNinjaGenerator* lg = this->LocalGenerator; std::vector<std::string> cleanFiles; - cmExpandList(cmGeneratorExpression::Evaluate(prop_value, lg, config, + cmExpandList(cmGeneratorExpression::Evaluate(*prop_value, lg, config, this->GeneratorTarget), cleanFiles); std::string const& binaryDir = lg->GetCurrentBinaryDirectory(); @@ -1494,9 +1641,9 @@ void cmNinjaTargetGenerator::addPoolNinjaVariable( const std::string& pool_property, cmGeneratorTarget* target, cmNinjaVars& vars) { - const char* pool = target->GetProperty(pool_property); + cmProp pool = target->GetProperty(pool_property); if (pool) { - vars["pool"] = pool; + vars["pool"] = *pool; } } diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 8678dc3f6..8d4372edc 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -12,7 +12,7 @@ #include <utility> #include <vector> -#include "cm_jsoncpp_value.h" +#include <cm3p/json/value.h> #include "cmCommonTargetGenerator.h" #include "cmGlobalNinjaGenerator.h" @@ -70,6 +70,8 @@ protected: const std::string& config) const; std::string LanguagePreprocessRule(std::string const& lang, const std::string& config) const; + std::string LanguageDependencyRule(std::string const& lang, + const std::string& config) const; bool NeedExplicitPreprocessing(std::string const& lang) const; std::string LanguageDyndepRule(std::string const& lang, const std::string& config) const; diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index 6e392421b..8d863c34d 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -17,6 +17,7 @@ #include "cmLocalNinjaGenerator.h" #include "cmNinjaTypes.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmSourceFile.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -110,9 +111,9 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config) std::string command = lg->BuildCommandLine(commands, "utility", this->GeneratorTarget); std::string desc; - const char* echoStr = genTarget->GetProperty("EchoString"); + cmProp echoStr = genTarget->GetProperty("EchoString"); if (echoStr) { - desc = echoStr; + desc = *echoStr; } else { desc = "Running utility command for " + this->GetTargetName(); } diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx index 382b563e2..7eea4b2df 100644 --- a/Source/cmOSXBundleGenerator.cxx +++ b/Source/cmOSXBundleGenerator.cxx @@ -56,9 +56,9 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, outpath = out; } -void cmOSXBundleGenerator::CreateFramework(const std::string& targetName, - const std::string& outpath, - const std::string& config) +void cmOSXBundleGenerator::CreateFramework( + const std::string& targetName, const std::string& outpath, + const std::string& config, const cmOSXBundleGenerator::SkipParts& skipParts) { if (this->MustSkip()) { return; @@ -77,16 +77,18 @@ void cmOSXBundleGenerator::CreateFramework(const std::string& targetName, 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()) { diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h index 232be4883..5bf1d9859 100644 --- a/Source/cmOSXBundleGenerator.h +++ b/Source/cmOSXBundleGenerator.h @@ -19,6 +19,15 @@ class cmOSXBundleGenerator public: 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, @@ -26,7 +35,8 @@ public: // create a framework at a given root void CreateFramework(const std::string& targetName, const std::string& root, - const std::string& config); + 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, diff --git a/Source/cmOptionCommand.cxx b/Source/cmOptionCommand.cxx index 22e59ac43..a58e2f8cc 100644 --- a/Source/cmOptionCommand.cxx +++ b/Source/cmOptionCommand.cxx @@ -6,6 +6,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" @@ -52,7 +53,7 @@ bool cmOptionCommand(std::vector<std::string> const& args, // See if a cache variable with this name already exists // If so just make sure the doc state is correct cmState* state = status.GetMakefile().GetState(); - const char* existingValue = state->GetCacheEntryValue(args[0]); + cmProp existingValue = state->GetCacheEntryValue(args[0]); if (existingValue && (state->GetCacheEntryType(args[0]) != cmStateEnums::UNINITIALIZED)) { state->SetCacheEntryProperty(args[0], "HELPSTRING", args[1]); @@ -60,7 +61,7 @@ bool cmOptionCommand(std::vector<std::string> const& args, } // Nothing in the cache so add it - std::string initialValue = existingValue ? existingValue : "Off"; + std::string initialValue = existingValue ? *existingValue : "Off"; if (args.size() == 3) { initialValue = args[2]; } diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 1c6fad148..359e9f5a9 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -26,7 +26,7 @@ std::string cmOutputConverter::ConvertToOutputForExisting( // already exists, we can use a short-path to reference it without a // space. if (this->GetState()->UseWindowsShell() && - remote.find(' ') != std::string::npos && + remote.find_first_of(" #") != std::string::npos && cmSystemTools::FileExists(remote)) { std::string tmp; if (cmSystemTools::GetShortPath(remote, tmp)) { @@ -170,13 +170,15 @@ cmOutputConverter::FortranFormat cmOutputConverter::GetFortranFormat( return format; } -cmOutputConverter::FortranFormat cmOutputConverter::GetFortranFormat( - const char* value) +cmOutputConverter::FortranPreprocess cmOutputConverter::GetFortranPreprocess( + cm::string_view value) { - if (!value) { - return FortranFormatNone; + if (value.empty()) { + return FortranPreprocess::Unset; } - return GetFortranFormat(cm::string_view(value)); + + return cmIsOn(value) ? FortranPreprocess::Needed + : FortranPreprocess::NotNeeded; } void cmOutputConverter::SetLinkScriptShell(bool linkScriptShell) diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 6583ab5cb..a8b452842 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -94,7 +94,14 @@ public: FortranFormatFree }; static FortranFormat GetFortranFormat(cm::string_view value); - static FortranFormat GetFortranFormat(const char* value); + + enum class FortranPreprocess + { + Unset, + NotNeeded, + Needed + }; + static FortranPreprocess GetFortranPreprocess(cm::string_view value); private: cmState* GetState() const; diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx index 147f97f73..aa5abcb7a 100644 --- a/Source/cmOutputRequiredFilesCommand.cxx +++ b/Source/cmOutputRequiredFilesCommand.cxx @@ -15,6 +15,7 @@ #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -117,14 +118,13 @@ public: std::set<std::string> uniqueIncludes; std::vector<std::string> orderedAndUniqueIncludes; for (auto const& target : this->Makefile->GetTargets()) { - const char* incDirProp = - target.second.GetProperty("INCLUDE_DIRECTORIES"); + cmProp incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES"); if (!incDirProp) { continue; } std::string incDirs = cmGeneratorExpression::Preprocess( - incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions); + *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions); std::vector<std::string> includes = cmExpandedList(incDirs); diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h index 81f8a49f6..121571603 100644 --- a/Source/cmPipeConnection.h +++ b/Source/cmPipeConnection.h @@ -6,7 +6,7 @@ #include <string> -#include "cm_uv.h" +#include <cm3p/uv.h> #include "cmConnection.h" #include "cmUVHandlePtr.h" diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 5c8bc98b2..dea3f8a35 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -72,6 +72,7 @@ static const char* idToVersion(cmPolicies::PolicyID id) #define POLICY_CASE(ID, V_MAJOR, V_MINOR, V_PATCH) \ case cmPolicies::ID: \ return #V_MAJOR "." #V_MINOR "." #V_PATCH; + // NOLINTNEXTLINE(bugprone-branch-clone) CM_FOR_EACH_POLICY_ID_VERSION(POLICY_CASE) #undef POLICY_CASE case cmPolicies::CMPCOUNT: @@ -90,6 +91,7 @@ static bool isPolicyNewerThan(cmPolicies::PolicyID id, unsigned int majorV, (majorV == (V_MAJOR) && minorV + 1 < (V_MINOR) + 1) || \ (majorV == (V_MAJOR) && minorV == (V_MINOR) && \ patchV + 1 < (V_PATCH) + 1)); + // NOLINTNEXTLINE(bugprone-branch-clone) CM_FOR_EACH_POLICY_ID_VERSION(POLICY_CASE) #undef POLICY_CASE case cmPolicies::CMPCOUNT: diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 1366ff089..a82f4211e 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -305,7 +305,22 @@ class cmMakefile; 17, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0102, \ "mark_as_advanced() does nothing if a cache entry does not exist.", \ - 3, 17, 0, cmPolicies::WARN) + 3, 17, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0103, \ + "Multiple export() with same FILE without APPEND is not allowed.", \ + 3, 18, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0104, \ + "CMAKE_CUDA_ARCHITECTURES now detected for NVCC, empty " \ + "CUDA_ARCHITECTURES not allowed.", \ + 3, 18, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0105, "Device link step uses the link options.", 3, 18, \ + 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0106, "The Documentation module is removed.", 3, 18, 0, \ + cmPolicies::WARN) \ + SELECT(POLICY, CMP0107, "An ALIAS target cannot overwrite another target.", \ + 3, 18, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0108, "A target cannot link to itself through an alias.", \ + 3, 18, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ @@ -335,7 +350,10 @@ class cmMakefile; F(CMP0081) \ F(CMP0083) \ F(CMP0095) \ - F(CMP0099) + F(CMP0099) \ + F(CMP0104) \ + F(CMP0105) \ + F(CMP0108) /** \class cmPolicies * \brief Handles changes in CMake behavior and policies diff --git a/Source/cmProcessOutput.cxx b/Source/cmProcessOutput.cxx index e80ea5c8d..0fb4ff71c 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 a25fd42d1..2ec66d9f1 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -47,10 +47,10 @@ bool cmProjectCommand(std::vector<std::string> const& args, 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()); @@ -66,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); } @@ -379,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/cmProperty.h b/Source/cmProperty.h index 80f131a76..b0fcce7f5 100644 --- a/Source/cmProperty.h +++ b/Source/cmProperty.h @@ -5,6 +5,8 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <string> + class cmProperty { public: @@ -22,4 +24,6 @@ public: }; }; +using cmProp = const std::string*; + #endif diff --git a/Source/cmPropertyDefinition.cxx b/Source/cmPropertyDefinition.cxx index 6a3174c7b..1796bb8d0 100644 --- a/Source/cmPropertyDefinition.cxx +++ b/Source/cmPropertyDefinition.cxx @@ -2,19 +2,38 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmPropertyDefinition.h" -void cmPropertyDefinition::DefineProperty(const std::string& name, - cmProperty::ScopeType scope, - const char* shortDescription, - const char* fullDescription, - bool chain) +#include <tuple> + +cmPropertyDefinition::cmPropertyDefinition(std::string shortDescription, + std::string fullDescription, + bool chained) + : ShortDescription(std::move(shortDescription)) + , FullDescription(std::move(fullDescription)) + , Chained(chained) +{ +} + +void cmPropertyDefinitionMap::DefineProperty( + const std::string& name, cmProperty::ScopeType scope, + const std::string& ShortDescription, const std::string& FullDescription, + bool chain) { - this->Name = name; - this->Scope = scope; - this->Chained = chain; - if (shortDescription) { - this->ShortDescription = shortDescription; + auto it = this->Map_.find(key_type(name, scope)); + if (it == this->Map_.end()) { + // try_emplace() since C++17 + this->Map_.emplace( + std::piecewise_construct, std::forward_as_tuple(name, scope), + std::forward_as_tuple(ShortDescription, FullDescription, chain)); } - if (fullDescription) { - this->FullDescription = fullDescription; +} + +cmPropertyDefinition const* cmPropertyDefinitionMap::GetPropertyDefinition( + const std::string& name, cmProperty::ScopeType scope) const +{ + auto it = this->Map_.find(key_type(name, scope)); + if (it != this->Map_.end()) { + return &it->second; } + + return nullptr; } diff --git a/Source/cmPropertyDefinition.h b/Source/cmPropertyDefinition.h index 0d68c328b..f83bc4f74 100644 --- a/Source/cmPropertyDefinition.h +++ b/Source/cmPropertyDefinition.h @@ -5,7 +5,9 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <map> #include <string> +#include <utility> #include "cmProperty.h" @@ -13,28 +15,19 @@ * \brief Property meta-information * * This class contains the following meta-information about property: - * - Name; * - Various documentation strings; - * - The scope of the property; * - If the property is chained. */ class cmPropertyDefinition { public: - /// Define this property - void DefineProperty(const std::string& name, cmProperty::ScopeType scope, - const char* ShortDescription, - const char* FullDescription, bool chained); - - /// Default constructor - cmPropertyDefinition() { this->Chained = false; } + /// Constructor + cmPropertyDefinition(std::string shortDescription, + std::string fullDescription, bool chained); /// Is the property chained? bool IsChained() const { return this->Chained; } - /// Get the scope - cmProperty::ScopeType GetScope() const { return this->Scope; } - /// Get the documentation (short version) const std::string& GetShortDescription() const { @@ -47,12 +40,30 @@ public: return this->FullDescription; } -protected: - std::string Name; +private: std::string ShortDescription; std::string FullDescription; - cmProperty::ScopeType Scope; bool Chained; }; +/** \class cmPropertyDefinitionMap + * \brief Map property name and scope to their definition + */ +class cmPropertyDefinitionMap +{ +public: + // define the property + void DefineProperty(const std::string& name, cmProperty::ScopeType scope, + const std::string& ShortDescription, + const std::string& FullDescription, bool chain); + + // get the property definition if present, otherwise nullptr + cmPropertyDefinition const* GetPropertyDefinition( + const std::string& name, cmProperty::ScopeType scope) const; + +private: + using key_type = std::pair<std::string, cmProperty::ScopeType>; + std::map<key_type, cmPropertyDefinition> Map_; +}; + #endif diff --git a/Source/cmPropertyDefinitionMap.cxx b/Source/cmPropertyDefinitionMap.cxx deleted file mode 100644 index f752ed7c6..000000000 --- a/Source/cmPropertyDefinitionMap.cxx +++ /dev/null @@ -1,35 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmPropertyDefinitionMap.h" - -#include <utility> - -void cmPropertyDefinitionMap::DefineProperty(const std::string& name, - cmProperty::ScopeType scope, - const char* ShortDescription, - const char* FullDescription, - bool chain) -{ - auto it = this->find(name); - cmPropertyDefinition* prop; - if (it == this->end()) { - prop = &(*this)[name]; - prop->DefineProperty(name, scope, ShortDescription, FullDescription, - chain); - } -} - -bool cmPropertyDefinitionMap::IsPropertyDefined(const std::string& name) const -{ - return this->find(name) != this->end(); -} - -bool cmPropertyDefinitionMap::IsPropertyChained(const std::string& name) const -{ - auto it = this->find(name); - if (it == this->end()) { - return false; - } - - return it->second.IsChained(); -} diff --git a/Source/cmPropertyDefinitionMap.h b/Source/cmPropertyDefinitionMap.h deleted file mode 100644 index 8ec791033..000000000 --- a/Source/cmPropertyDefinitionMap.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmPropertyDefinitionMap_h -#define cmPropertyDefinitionMap_h - -#include "cmConfigure.h" // IWYU pragma: keep - -#include <map> -#include <string> - -#include "cmProperty.h" -#include "cmPropertyDefinition.h" - -class cmPropertyDefinitionMap - : public std::map<std::string, cmPropertyDefinition> -{ -public: - // define the property - void DefineProperty(const std::string& name, cmProperty::ScopeType scope, - const char* ShortDescription, - const char* FullDescription, bool chain); - - // has a named property been defined - bool IsPropertyDefined(const std::string& name) const; - - // is a named property set to chain - bool IsPropertyChained(const std::string& name) const; -}; - -#endif diff --git a/Source/cmPropertyMap.cxx b/Source/cmPropertyMap.cxx index d4b35523f..f22f36dd4 100644 --- a/Source/cmPropertyMap.cxx +++ b/Source/cmPropertyMap.cxx @@ -42,13 +42,11 @@ void cmPropertyMap::RemoveProperty(const std::string& name) Map_.erase(name); } -const char* cmPropertyMap::GetPropertyValue(const std::string& name) const +cmProp cmPropertyMap::GetPropertyValue(const std::string& name) const { - { - auto it = Map_.find(name); - if (it != Map_.end()) { - return it->second.c_str(); - } + auto it = Map_.find(name); + if (it != Map_.end()) { + return &it->second; } return nullptr; } diff --git a/Source/cmPropertyMap.h b/Source/cmPropertyMap.h index bea437284..5fc46a2b4 100644 --- a/Source/cmPropertyMap.h +++ b/Source/cmPropertyMap.h @@ -10,6 +10,8 @@ #include <utility> #include <vector> +#include "cmProperty.h" + /** \class cmPropertyMap * \brief String property map. */ @@ -31,7 +33,7 @@ public: bool asString = false); //! Get the property value - const char* GetPropertyValue(const std::string& name) const; + cmProp GetPropertyValue(const std::string& name) const; //! Remove the property @a name from the map void RemoveProperty(const std::string& name); diff --git a/Source/cmQTWrapCPPCommand.cxx b/Source/cmQTWrapCPPCommand.cxx index cc4df8f89..795c2ee5a 100644 --- a/Source/cmQTWrapCPPCommand.cxx +++ b/Source/cmQTWrapCPPCommand.cxx @@ -5,6 +5,7 @@ #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" @@ -39,7 +40,8 @@ bool cmQTWrapCPPCommand(std::vector<std::string> const& args, cmStrCat(mf.GetCurrentBinaryDirectory(), "/moc_", srcName, ".cxx"); cmSourceFile* sf = mf.GetOrCreateSource(newName, true); if (curr) { - sf->SetProperty("ABSTRACT", curr->GetProperty("ABSTRACT")); + cmProp p = curr->GetProperty("ABSTRACT"); + sf->SetProperty("ABSTRACT", p ? p->c_str() : nullptr); } // Compute the name of the header from which to generate the file. diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index d5891c447..57fcd2da7 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -13,7 +13,6 @@ #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmDuration.h" #include "cmProcessOutput.h" #include "cmStringAlgorithms.h" @@ -55,7 +54,7 @@ void MergeOptions(std::vector<std::string>& baseOpts, } } // Test if this is a value option and change the existing value - if (!optName.empty() && cmContains(valueOpts, optName)) { + if (!optName.empty() && cm::contains(valueOpts, optName)) { const auto existItNext(existIt + 1); const auto fitNext(fit + 1); if ((existItNext != baseOpts.end()) && (fitNext != fitEnd)) { diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx index 7a6cb4219..3d4f5d722 100644 --- a/Source/cmQtAutoGenGlobalInitializer.cxx +++ b/Source/cmQtAutoGenGlobalInitializer.cxx @@ -13,6 +13,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmProcessOutput.h" +#include "cmProperty.h" #include "cmQtAutoGen.h" #include "cmQtAutoGenInitializer.h" #include "cmState.h" @@ -95,11 +96,11 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( bool const uic = target->GetPropertyAsBool(kw().AUTOUIC); bool const rcc = target->GetPropertyAsBool(kw().AUTORCC); if (moc || uic || rcc) { - std::string const mocExec = + std::string const& mocExec = target->GetSafeProperty(kw().AUTOMOC_EXECUTABLE); - std::string const uicExec = + std::string const& uicExec = target->GetSafeProperty(kw().AUTOUIC_EXECUTABLE); - std::string const rccExec = + std::string const& rccExec = target->GetSafeProperty(kw().AUTORCC_EXECUTABLE); // We support Qt4, Qt5 and Qt6 @@ -164,10 +165,10 @@ void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget( // Set FOLDER property in the target { - char const* folder = + cmProp folder = makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER"); if (folder != nullptr) { - target->SetProperty("FOLDER", folder); + target->SetProperty("FOLDER", *folder); } } } diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index d8b91001e..511a018fb 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -16,13 +16,13 @@ #include <cm/algorithm> #include <cm/iterator> #include <cm/memory> +#include <cmext/algorithm> -#include "cmsys/SystemInformation.hxx" +#include <cm3p/json/value.h> +#include <cm3p/json/writer.h> -#include "cm_jsoncpp_value.h" -#include "cm_jsoncpp_writer.h" +#include "cmsys/SystemInformation.hxx" -#include "cmAlgorithms.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmGeneratedFileStream.h" @@ -35,6 +35,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmQtAutoGen.h" #include "cmQtAutoGenGlobalInitializer.h" #include "cmSourceFile.h" @@ -339,7 +340,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets() // Targets FOLDER { - const char* folder = + cmProp folder = this->Makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER"); if (folder == nullptr) { folder = this->Makefile->GetState()->GetGlobalProperty( @@ -350,7 +351,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets() folder = this->GenTarget->GetProperty("FOLDER"); } if (folder != nullptr) { - this->TargetsFolder = folder; + this->TargetsFolder = *folder; } } @@ -440,7 +441,8 @@ bool cmQtAutoGenInitializer::InitCustomTargets() // Autogen target parallel processing { - std::string prop = this->GenTarget->GetSafeProperty("AUTOGEN_PARALLEL"); + std::string const& prop = + this->GenTarget->GetSafeProperty("AUTOGEN_PARALLEL"); if (prop.empty() || (prop == "AUTO")) { // Autodetect number of CPUs this->AutogenTarget.Parallel = GetParallelCPUCount(); @@ -471,7 +473,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets() this->AutogenTarget.DependOrigin = this->GenTarget->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS"); - std::string const deps = + std::string const& deps = this->GenTarget->GetSafeProperty("AUTOGEN_TARGET_DEPENDS"); if (!deps.empty()) { for (std::string const& depName : cmExpandedList(deps)) { @@ -569,9 +571,8 @@ bool cmQtAutoGenInitializer::InitMoc() if (this->GenTarget->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && (this->QtVersion >= IntegerVersion(5, 8))) { // Command - cmExpandList(this->Makefile->GetSafeDefinition( - "CMAKE_CXX_COMPILER_PREDEFINES_COMMAND"), - this->Moc.PredefsCmd); + this->Makefile->GetDefExpandList("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND", + this->Moc.PredefsCmd); // Header if (!this->Moc.PredefsCmd.empty()) { ConfigFileNames(this->Moc.PredefsFile, @@ -654,7 +655,7 @@ bool cmQtAutoGenInitializer::InitUic() { // Uic search paths { - std::string const usp = + std::string const& usp = this->GenTarget->GetSafeProperty("AUTOUIC_SEARCH_PATHS"); if (!usp.empty()) { this->Uic.SearchPaths = @@ -847,7 +848,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() this->Makefile->GetSource(fullPath, locationKind); if (sf != nullptr) { // Check if we know about this header already - if (cmContains(this->AutogenTarget.Headers, sf)) { + if (cm::contains(this->AutogenTarget.Headers, sf)) { continue; } // We only accept not-GENERATED files that do exist. @@ -895,14 +896,14 @@ bool cmQtAutoGenInitializer::InitScanFiles() cmSystemTools::LowerCase(sf->GetExtension()); if (cm->IsHeaderExtension(extLower)) { - if (!cmContains(this->AutogenTarget.Headers, sf.get())) { + if (!cm::contains(this->AutogenTarget.Headers, sf.get())) { auto muf = makeMUFile(sf.get(), fullPath, false); if (muf->SkipMoc || muf->SkipUic) { addMUHeader(std::move(muf), extLower); } } } else if (cm->IsSourceExtension(extLower)) { - if (!cmContains(this->AutogenTarget.Sources, sf.get())) { + if (!cm::contains(this->AutogenTarget.Sources, sf.get())) { auto muf = makeMUFile(sf.get(), fullPath, false); if (muf->SkipMoc || muf->SkipUic) { addMUSource(std::move(muf)); @@ -1094,6 +1095,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // of fiddling with the include directories std::vector<std::string> configs; this->GlobalGen->GetQtAutoGenConfigs(configs); + bool stdPipesUTF8 = true; cmCustomCommandLines commandLines; for (auto const& config : configs) { commandLines.push_back(cmMakeCommandLine( @@ -1138,7 +1140,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() const std::vector<std::string> no_deps; cmCustomCommand cc(no_output, autogenProvides, no_deps, commandLines, this->Makefile->GetBacktrace(), autogenComment.c_str(), - this->Dir.Work.c_str()); + this->Dir.Work.c_str(), stdPipesUTF8); cc.SetEscapeOldStyle(false); cc.SetEscapeAllowMakeVars(true); this->GenTarget->Target->AddPreBuildCommand(std::move(cc)); @@ -1180,54 +1182,11 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() if (useNinjaDepfile) { // Create a custom command that generates a timestamp file and // has a depfile assigned. The depfile is created by JobDepFilesMergeT. - // - // Also create an additional '_autogen_timestamp_deps' that the custom - // command will depend on. It will have no sources or commands to - // execute, but it will have dependencies that would originally be - // assigned to the pre-Qt 5.15 'autogen' target. These dependencies will - // serve as a list of order-only dependencies for the custom command, - // without forcing the custom command to re-execute. - // - // The dependency tree would then look like - // '_autogen_timestamp_deps (order-only)' <- '/timestamp' file <- - // '_autogen' target. - const auto timestampTargetName = - cmStrCat(this->GenTarget->GetName(), "_autogen_timestamp_deps"); - std::vector<std::string> timestampTargetProvides; - cmCustomCommandLines timestampTargetCommandLines; - - // Add additional autogen target dependencies to - // '_autogen_timestamp_deps'. + + // Add additional autogen target dependencies for (const cmTarget* t : this->AutogenTarget.DependTargets) { dependencies.push_back(t->GetName()); } - - cmTarget* timestampTarget = this->LocalGen->AddUtilityCommand( - timestampTargetName, true, this->Dir.Work.c_str(), - /*byproducts=*/timestampTargetProvides, - /*depends=*/dependencies, timestampTargetCommandLines, false, nullptr); - this->LocalGen->AddGeneratorTarget( - cm::make_unique<cmGeneratorTarget>(timestampTarget, this->LocalGen)); - - // Set FOLDER property on the timestamp target, so it appears in the - // appropriate folder in an IDE or in the file api. - if (!this->TargetsFolder.empty()) { - timestampTarget->SetProperty("FOLDER", this->TargetsFolder); - } - - // Make '/timestamp' file depend on '_autogen_timestamp_deps' and on the - // moc and uic executables (whichever are enabled). - dependencies.clear(); - dependencies.push_back(timestampTargetName); - - if (this->Moc.ExecutableTarget != nullptr) { - dependencies.push_back(this->Moc.ExecutableTarget->Target->GetName()); - } - if (this->Uic.ExecutableTarget != nullptr) { - dependencies.push_back(this->Uic.ExecutableTarget->Target->GetName()); - } - - // Create the custom command that outputs the timestamp file. const char timestampFileName[] = "timestamp"; const std::string outputFile = cmStrCat(this->Dir.Build, "/", timestampFileName); @@ -1251,7 +1210,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() autogenComment.c_str(), this->Dir.Work.c_str(), /*replace=*/false, /*escapeOldStyle=*/false, /*uses_terminal=*/false, - /*command_expand_lists=*/false, this->AutogenTarget.DepFile); + /*command_expand_lists=*/false, this->AutogenTarget.DepFile, "", + stdPipesUTF8); // Alter variables for the autogen target which now merely wraps the // custom command @@ -1322,6 +1282,7 @@ bool cmQtAutoGenInitializer::InitRccTargets() ccDepends.push_back(qrc.QrcFile); ccDepends.push_back(qrc.InfoFile); + bool stdPipesUTF8 = true; cmCustomCommandLines commandLines; if (this->MultiConfig) { // Build for all configurations @@ -1350,7 +1311,8 @@ bool cmQtAutoGenInitializer::InitRccTargets() cmTarget* autoRccTarget = this->LocalGen->AddUtilityCommand( ccName, true, this->Dir.Work.c_str(), ccOutput, ccDepends, - commandLines, false, ccComment.c_str()); + commandLines, false, ccComment.c_str(), false, false, "", + stdPipesUTF8); // Create autogen generator target this->LocalGen->AddGeneratorTarget( @@ -1390,7 +1352,8 @@ bool cmQtAutoGenInitializer::InitRccTargets() this->LocalGen->AddCustomCommandToOutput( ccOutput, ccByproducts, ccDepends, no_main_dependency, no_implicit_depends, commandLines, ccComment.c_str(), - this->Dir.Work.c_str()); + this->Dir.Work.c_str(), false, true, false, false, "", "", + stdPipesUTF8); } // Reconfigure when .qrc file changes this->Makefile->AddCMakeDependFile(qrc.QrcFile); @@ -1508,7 +1471,6 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() 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("CMAKE_LIST_FILES", this->Makefile->GetListFiles()); info.SetArray("HEADER_EXTENSIONS", this->Makefile->GetCMakeInstance()->GetHeaderExtensions()); info.SetArrayArray( @@ -1648,10 +1610,9 @@ void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName, cmStrCat(genNameUpper, "_SOURCE_GROUP"), "AUTOGEN_SOURCE_GROUP" }; for (std::string const& prop : props) { - const char* propName = - this->Makefile->GetState()->GetGlobalProperty(prop); - if ((propName != nullptr) && (*propName != '\0')) { - groupName = propName; + cmProp propName = this->Makefile->GetState()->GetGlobalProperty(prop); + if (propName && !propName->empty()) { + groupName = *propName; property = prop; break; } @@ -1712,6 +1673,13 @@ cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target) } return 0u; }; + auto toUInt2 = [](cmProp input) -> unsigned int { + unsigned long tmp = 0; + if (input != nullptr && cmStrToULong(*input, &tmp)) { + return static_cast<unsigned int>(tmp); + } + return 0u; + }; // Initialize return value to a default std::pair<IntegerVersion, unsigned int> res( @@ -1733,9 +1701,9 @@ cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target) knownQtVersions.reserve(keys.size() * 2); // Adds a version to the result (nullptr safe) - auto addVersion = [&knownQtVersions, &toUInt](const char* major, - const char* minor) { - cmQtAutoGen::IntegerVersion ver(toUInt(major), toUInt(minor)); + auto addVersion = [&knownQtVersions, &toUInt2](cmProp major, + cmProp minor) { + cmQtAutoGen::IntegerVersion ver(toUInt2(major), toUInt2(minor)); if (ver.Major != 0) { knownQtVersions.emplace_back(ver); } @@ -1743,8 +1711,8 @@ cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target) // Read versions from variables for (auto const& keyPair : keys) { - addVersion(target->Makefile->GetDefinition(std::string(keyPair.first)), - target->Makefile->GetDefinition(std::string(keyPair.second))); + addVersion(target->Makefile->GetDef(std::string(keyPair.first)), + target->Makefile->GetDef(std::string(keyPair.second))); } // Read versions from directory properties @@ -1827,7 +1795,7 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars, // Custom executable { std::string const prop = cmStrCat(genVars.GenNameUpper, "_EXECUTABLE"); - std::string const val = this->GenTarget->Target->GetSafeProperty(prop); + std::string const& val = this->GenTarget->Target->GetSafeProperty(prop); if (!val.empty()) { // Evaluate generator expression { diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index da963052f..ee2bc0937 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -2,9 +2,9 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGenerator.h" -#include "cmsys/FStream.hxx" +#include <cm3p/json/reader.h> -#include "cm_jsoncpp_reader.h" +#include "cmsys/FStream.hxx" #include "cmQtAutoGen.h" #include "cmStringAlgorithms.h" diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h index bbe6dd015..83fb3ed88 100644 --- a/Source/cmQtAutoGenerator.h +++ b/Source/cmQtAutoGenerator.h @@ -13,7 +13,7 @@ #include <cm/string_view> -#include "cm_jsoncpp_value.h" +#include <cm3p/json/value.h> #include "cmFileTime.h" #include "cmQtAutoGen.h" diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 49eb018e7..9adcabb80 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -18,11 +18,11 @@ #include <cm/string_view> #include <cmext/algorithm> +#include <cm3p/json/value.h> + #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" -#include "cm_jsoncpp_value.h" - #include "cmCryptoHash.h" #include "cmFileTime.h" #include "cmGccDepfileReader.h" @@ -184,7 +184,6 @@ public: std::string DepFile; std::string DepFileRuleName; std::vector<std::string> HeaderExtensions; - std::vector<std::string> ListFiles; }; /** Shared common variables. */ @@ -701,27 +700,27 @@ bool cmQtAutoMocUicT::ParseCacheT::WriteToFile(std::string const& fileName) if (!ofs) { return false; } - ofs << "# Generated by CMake. Changes will be overwritten." << std::endl; + ofs << "# Generated by CMake. Changes will be overwritten.\n"; for (auto const& pair : Map_) { - ofs << pair.first << std::endl; + ofs << pair.first << '\n'; FileT const& file = *pair.second; if (!file.Moc.Macro.empty()) { - ofs << " mmc:" << file.Moc.Macro << std::endl; + ofs << " mmc:" << file.Moc.Macro << '\n'; } for (IncludeKeyT const& item : file.Moc.Include.Underscore) { - ofs << " miu:" << item.Key << std::endl; + ofs << " miu:" << item.Key << '\n'; } for (IncludeKeyT const& item : file.Moc.Include.Dot) { - ofs << " mid:" << item.Key << std::endl; + ofs << " mid:" << item.Key << '\n'; } for (std::string const& item : file.Moc.Depends) { - ofs << " mdp:" << item << std::endl; + ofs << " mdp:" << item << '\n'; } for (IncludeKeyT const& item : file.Uic.Include) { - ofs << " uic:" << item.Key << std::endl; + ofs << " uic:" << item.Key << '\n'; } for (std::string const& item : file.Uic.Depends) { - ofs << " udp:" << item << std::endl; + ofs << " udp:" << item << '\n'; } } return ofs.Close(); @@ -2164,9 +2163,7 @@ std::string escapeDependencyPath(cm::string_view path) void cmQtAutoMocUicT::JobDepFilesMergeT::Process() { if (Log().Verbose()) { - Log().Info(GenT::MOC, - cmStrCat("Merging MOC dependencies into ", - MessagePath(BaseConst().DepFile.c_str()))); + Log().Info(GenT::MOC, "Merging MOC dependencies"); } auto processDepFile = [](const std::string& mocOutputFile) -> std::vector<std::string> { @@ -2177,7 +2174,7 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process() return dependenciesFromDepFile(f.c_str()); }; - std::vector<std::string> dependencies = BaseConst().ListFiles; + std::vector<std::string> dependencies; ParseCacheT& parseCache = BaseEval().ParseCache; auto processMappingEntry = [&](const MappingMapT::value_type& m) { auto cacheEntry = parseCache.GetOrInsert(m.first); @@ -2214,9 +2211,9 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process() " for writing.")); return; } - ofs << BaseConst().DepFileRuleName << ": \\" << std::endl; + ofs << BaseConst().DepFileRuleName << ": \\\n"; for (const std::string& file : dependencies) { - ofs << '\t' << escapeDependencyPath(file) << " \\" << std::endl; + ofs << '\t' << escapeDependencyPath(file) << " \\\n"; if (!ofs.good()) { LogError(GenT::GEN, cmStrCat("Writing depfile", MessagePath(BaseConst().DepFile), @@ -2227,8 +2224,7 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process() // 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; + ofs << '\t' << escapeDependencyPath(BaseConst().CMakeExecutable) << '\n'; } void cmQtAutoMocUicT::JobFinishT::Process() @@ -2259,7 +2255,6 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) !info.GetString("DEP_FILE_RULE_NAME", BaseConst_.DepFileRuleName, false) || !info.GetStringConfig("SETTINGS_FILE", SettingsFile_, true) || - !info.GetArray("CMAKE_LIST_FILES", BaseConst_.ListFiles, true) || !info.GetArray("HEADER_EXTENSIONS", BaseConst_.HeaderExtensions, true) || !info.GetString("QT_MOC_EXECUTABLE", MocConst_.Executable, false) || !info.GetString("QT_UIC_EXECUTABLE", UicConst_.Executable, false)) { diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx index 7f4abf904..26e93bb34 100644 --- a/Source/cmRST.cxx +++ b/Source/cmRST.cxx @@ -89,7 +89,8 @@ void cmRST::ProcessModule(std::istream& is) this->ProcessLine(line); } else { if (line[0] != '#') { - this->ProcessLine(line.substr(0, pos)); + line.resize(pos); + this->ProcessLine(line); } rst.clear(); this->Reset(); @@ -102,8 +103,9 @@ void cmRST::ProcessModule(std::istream& is) this->ProcessLine(""); continue; } - if (line.substr(0, 2) == "# ") { - this->ProcessLine(line.substr(2)); + if (cmHasLiteralPrefix(line, "# ")) { + line.erase(0, 2); + this->ProcessLine(line); continue; } rst.clear(); @@ -164,6 +166,8 @@ void cmRST::ProcessLine(std::string const& line) this->Markup = (line.find_first_not_of(" \t", 2) == std::string::npos ? MarkupEmpty : MarkupNormal); + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) if (this->CMakeDirective.find(line)) { // Output cmake domain directives and their content normally. this->NormalLine(line); diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index 5ab1b3ac1..254131b4d 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -236,8 +236,7 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( } if (variable == "CMAKE_COMMAND") { return outputConverter->ConvertToOutputFormat( - cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()), - cmOutputConverter::SHELL); + cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); } auto compIt = this->Compilers.find(variable); @@ -334,7 +333,17 @@ void cmRulePlaceholderExpander::ExpandRuleVariables( std::string replace = this->ExpandRuleVariable(outputConverter, var, replaceValues); expandedInput += s.substr(pos, start - pos); + + // Prevent consecutive whitespace in the output if the rule variable + // expands to an empty string. + bool consecutive = replace.empty() && start > 0 && s[start - 1] == ' ' && + end + 1 < s.size() && s[end + 1] == ' '; + if (consecutive) { + expandedInput.pop_back(); + } + expandedInput += replace; + // move to next one start = s.find('<', start + var.size() + 2); pos = end + 1; diff --git a/Source/cmRuntimeDependencyArchive.cxx b/Source/cmRuntimeDependencyArchive.cxx index 7a987c27e..0781d2978 100644 --- a/Source/cmRuntimeDependencyArchive.cxx +++ b/Source/cmRuntimeDependencyArchive.cxx @@ -39,7 +39,7 @@ static void AddVisualStudioPath(std::vector<std::string>& paths, std::string vsloc; bool found = false; # ifndef CMAKE_BOOTSTRAP - if (gg->GetName().find(prefix) == 0) { + if (cmHasPrefix(gg->GetName(), prefix)) { cmGlobalVisualStudioVersionedGenerator* vsgen = static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg); if (vsgen->GetVSInstance(vsloc)) { @@ -218,6 +218,9 @@ bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand( // First see if it was supplied by the user std::string toolCommand = this->GetMakefile()->GetSafeDefinition( "CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND"); + if (toolCommand.empty() && search == "objdump") { + toolCommand = this->GetMakefile()->GetSafeDefinition("CMAKE_OBJDUMP"); + } if (!toolCommand.empty()) { cmExpandList(toolCommand, command); return true; diff --git a/Source/cmSeparateArgumentsCommand.cxx b/Source/cmSeparateArgumentsCommand.cxx index 52bde7c5c..cfe308755 100644 --- a/Source/cmSeparateArgumentsCommand.cxx +++ b/Source/cmSeparateArgumentsCommand.cxx @@ -39,6 +39,8 @@ bool cmSeparateArgumentsCommand(std::vector<std::string> const& args, if (doing == DoingVariable) { var = arg; doing = DoingMode; + // This will always clone one of the other blocks. + // NOLINTNEXTLINE(bugprone-branch-clone) } else if (doing == DoingMode && arg == "NATIVE_COMMAND") { #ifdef _WIN32 mode = ModeWindows; diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx index 3b2e5f322..7f9740626 100644 --- a/Source/cmServer.cxx +++ b/Source/cmServer.cxx @@ -4,6 +4,7 @@ #include <algorithm> #include <cassert> +#include <csignal> #include <cstdint> #include <iostream> #include <mutex> @@ -12,10 +13,10 @@ #include <cm/memory> #include <cm/shared_mutex> -#include "cmsys/FStream.hxx" +#include <cm3p/json/reader.h> +#include <cm3p/json/writer.h> -#include "cm_jsoncpp_reader.h" -#include "cm_jsoncpp_writer.h" +#include "cmsys/FStream.hxx" #include "cmConnection.h" #include "cmFileMonitor.h" @@ -59,16 +60,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 +114,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 +294,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 3d7027b39..954332908 100644 --- a/Source/cmServer.h +++ b/Source/cmServer.h @@ -10,8 +10,8 @@ #include <cm/shared_mutex> -#include "cm_jsoncpp_value.h" -#include "cm_uv.h" +#include <cm3p/json/value.h> +#include <cm3p/uv.h> #include "cmUVHandlePtr.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/cmServerConnection.cxx b/Source/cmServerConnection.cxx index 279197214..b4f41a09e 100644 --- a/Source/cmServerConnection.cxx +++ b/Source/cmServerConnection.cxx @@ -4,7 +4,7 @@ #include "cmServerConnection.h" -#include "cm_uv.h" +#include <cm3p/uv.h> #include "cmServer.h" #include "cmServerDictionary.h" diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index 1d4ea0153..4f7131fc6 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -10,16 +10,17 @@ #include <vector> #include <cm/memory> +#include <cmext/algorithm> -#include "cm_uv.h" +#include <cm3p/uv.h> -#include "cmAlgorithms.h" #include "cmExternalMakefileProjectGenerator.h" #include "cmFileMonitor.h" #include "cmGlobalGenerator.h" #include "cmJsonObjectDictionary.h" #include "cmJsonObjects.h" #include "cmMessageType.h" +#include "cmProperty.h" #include "cmServer.h" #include "cmServerDictionary.h" #include "cmState.h" @@ -182,7 +183,7 @@ static bool getOrTestHomeDirectory(cmState* state, std::string& value, std::string* errorMessage) { const std::string cachedValue = - std::string(state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY")); + *state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY"); if (value.empty()) { value = cachedValue; return true; @@ -205,9 +206,7 @@ static bool getOrTestValue(cmState* state, const std::string& key, const std::string& keyDescription, std::string* errorMessage) { - const char* entry = state->GetCacheEntryValue(key); - const std::string cachedValue = - entry == nullptr ? std::string() : std::string(entry); + const std::string cachedValue = state->GetSafeCacheEntryValue(key); if (value.empty()) { value = cachedValue; } @@ -435,7 +434,7 @@ cmServerResponse cmServerProtocol1::ProcessCache( keys = allKeys; } else { for (auto const& i : keys) { - if (!cmContains(allKeys, i)) { + if (!cm::contains(allKeys, i)) { return request.ReportError("Key \"" + i + "\" not found in cache."); } } @@ -446,13 +445,13 @@ cmServerResponse cmServerProtocol1::ProcessCache( entry[kKEY_KEY] = key; entry[kTYPE_KEY] = cmState::CacheEntryTypeToString(state->GetCacheEntryType(key)); - entry[kVALUE_KEY] = state->GetCacheEntryValue(key); + entry[kVALUE_KEY] = *state->GetCacheEntryValue(key); Json::Value props = Json::objectValue; bool haveProperties = false; for (auto const& prop : state->GetCacheEntryPropertyList(key)) { haveProperties = true; - props[prop] = state->GetCacheEntryProperty(key, prop); + props[prop] = *state->GetCacheEntryProperty(key, prop); } if (haveProperties) { entry[kPROPERTIES_KEY] = props; @@ -564,7 +563,7 @@ cmServerResponse cmServerProtocol1::ProcessConfigure( if (cm->LoadCache(buildDir)) { // build directory has been set up before - const std::string* cachedSourceDir = + cmProp cachedSourceDir = cm->GetState()->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY"); if (!cachedSourceDir) { return request.ReportError("No CMAKE_HOME_DIRECTORY found in cache."); @@ -574,7 +573,7 @@ cmServerResponse cmServerProtocol1::ProcessConfigure( cm->SetHomeDirectory(sourceDir); } - const std::string* cachedGenerator = + cmProp cachedGenerator = cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR"); if (cachedGenerator) { if (gg && gg->GetName() != *cachedGenerator) { diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h index 8446c3e76..c71b7bf60 100644 --- a/Source/cmServerProtocol.h +++ b/Source/cmServerProtocol.h @@ -8,7 +8,7 @@ #include <string> #include <utility> -#include "cm_jsoncpp_value.h" +#include <cm3p/json/value.h> #include "cmake.h" diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx index 5e2a1462c..354b4c327 100644 --- a/Source/cmSetCommand.cxx +++ b/Source/cmSetCommand.cxx @@ -5,6 +5,7 @@ #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmState.h" #include "cmStateTypes.h" @@ -135,7 +136,7 @@ bool cmSetCommand(std::vector<std::string> const& args, // see if this is already in the cache cmState* state = status.GetMakefile().GetState(); - const char* existingValue = state->GetCacheEntryValue(variable); + cmProp existingValue = state->GetCacheEntryValue(variable); if (existingValue && (state->GetCacheEntryType(variable) != cmStateEnums::UNINITIALIZED)) { // if the set is trying to CACHE the value but the value @@ -149,8 +150,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/cmSetDirectoryPropertiesCommand.cxx b/Source/cmSetDirectoryPropertiesCommand.cxx index 35daca6ff..07ad24602 100644 --- a/Source/cmSetDirectoryPropertiesCommand.cxx +++ b/Source/cmSetDirectoryPropertiesCommand.cxx @@ -5,12 +5,6 @@ #include "cmExecutionStatus.h" #include "cmMakefile.h" -namespace { -bool RunCommand(cmMakefile& mf, std::vector<std::string>::const_iterator ait, - std::vector<std::string>::const_iterator aitend, - std::string& errors); -} - // cmSetDirectoryPropertiesCommand bool cmSetDirectoryPropertiesCommand(std::vector<std::string> const& args, cmExecutionStatus& status) @@ -20,38 +14,26 @@ bool cmSetDirectoryPropertiesCommand(std::vector<std::string> const& args, return false; } - std::string errors; - bool ret = - RunCommand(status.GetMakefile(), args.begin() + 1, args.end(), errors); - if (!ret) { - status.SetError(errors); + // PROPERTIES followed by prop value pairs + if (args.size() % 2 != 1) { + status.SetError("Wrong number of arguments"); + return false; } - return ret; -} -namespace { -bool RunCommand(cmMakefile& mf, std::vector<std::string>::const_iterator ait, - std::vector<std::string>::const_iterator aitend, - std::string& errors) -{ - for (; ait != aitend; ait += 2) { - if (ait + 1 == aitend) { - errors = "Wrong number of arguments"; - return false; - } - const std::string& prop = *ait; - const std::string& value = *(ait + 1); + for (auto iter = args.begin() + 1; iter != args.end(); iter += 2) { + const std::string& prop = *iter; if (prop == "VARIABLES") { - errors = "Variables and cache variables should be set using SET command"; + status.SetError( + "Variables and cache variables should be set using SET command"); return false; } if (prop == "MACROS") { - errors = "Commands and macros cannot be set using SET_CMAKE_PROPERTIES"; + status.SetError( + "Commands and macros cannot be set using SET_CMAKE_PROPERTIES"); return false; } - mf.SetProperty(prop, value.c_str()); + status.GetMakefile().SetProperty(prop, (iter + 1)->c_str()); } return true; } -} diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx index 3705727d8..6ca763b0b 100644 --- a/Source/cmSetPropertyCommand.cxx +++ b/Source/cmSetPropertyCommand.cxx @@ -4,6 +4,7 @@ #include <set> #include <sstream> +#include <unordered_set> #include "cmExecutionStatus.h" #include "cmGlobalGenerator.h" @@ -43,7 +44,9 @@ bool HandleSourceMode(cmExecutionStatus& status, const std::set<std::string>& names, const std::string& propertyName, const std::string& propertyValue, bool appendAsString, - bool appendMode, bool remove); + bool appendMode, bool remove, + const std::vector<cmMakefile*>& directory_makefiles, + bool source_file_paths_should_be_absolute); bool HandleSource(cmSourceFile* sf, const std::string& propertyName, const std::string& propertyValue, bool appendAsString, bool appendMode, bool remove); @@ -74,6 +77,147 @@ bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile, bool appendMode, bool remove); } +namespace SetPropertyCommand { +bool HandleSourceFileDirectoryScopes( + cmExecutionStatus& status, std::vector<std::string>& source_file_directories, + std::vector<std::string>& source_file_target_directories, + std::vector<cmMakefile*>& directory_makefiles) +{ + std::unordered_set<cmMakefile*> directory_makefiles_set; + + cmMakefile* current_dir_mf = &status.GetMakefile(); + if (!source_file_directories.empty()) { + for (const std::string& dir_path : source_file_directories) { + const std::string absolute_dir_path = cmSystemTools::CollapseFullPath( + dir_path, current_dir_mf->GetCurrentSourceDirectory()); + cmMakefile* dir_mf = + status.GetMakefile().GetGlobalGenerator()->FindMakefile( + absolute_dir_path); + if (!dir_mf) { + status.SetError(cmStrCat("given non-existent DIRECTORY ", dir_path)); + return false; + } + if (directory_makefiles_set.find(dir_mf) == + directory_makefiles_set.end()) { + directory_makefiles.push_back(dir_mf); + directory_makefiles_set.insert(dir_mf); + } + } + } + + if (!source_file_target_directories.empty()) { + for (const std::string& target_name : source_file_target_directories) { + cmTarget* target = current_dir_mf->FindTargetToUse(target_name); + if (!target) { + status.SetError(cmStrCat( + "given non-existent target for TARGET_DIRECTORY ", target_name)); + return false; + } + cmProp target_source_dir = target->GetProperty("SOURCE_DIR"); + cmMakefile* target_dir_mf = + status.GetMakefile().GetGlobalGenerator()->FindMakefile( + *target_source_dir); + + if (directory_makefiles_set.find(target_dir_mf) == + directory_makefiles_set.end()) { + directory_makefiles.push_back(target_dir_mf); + directory_makefiles_set.insert(target_dir_mf); + } + } + } + + if (source_file_directories.empty() && + source_file_target_directories.empty()) { + directory_makefiles.push_back(current_dir_mf); + } + return true; +} + +bool HandleSourceFileDirectoryScopeValidation( + cmExecutionStatus& status, bool source_file_directory_option_enabled, + bool source_file_target_option_enabled, + std::vector<std::string>& source_file_directories, + std::vector<std::string>& source_file_target_directories) +{ + // Validate source file directory scopes. + if (source_file_directory_option_enabled && + source_file_directories.empty()) { + std::string errors = "called with incorrect number of arguments " + "no value provided to the DIRECTORY option"; + status.SetError(errors); + return false; + } + if (source_file_target_option_enabled && + source_file_target_directories.empty()) { + std::string errors = "called with incorrect number of arguments " + "no value provided to the TARGET_DIRECTORY option"; + status.SetError(errors); + return false; + } + return true; +} + +bool HandleAndValidateSourceFileDirectortoryScopes( + cmExecutionStatus& status, bool source_file_directory_option_enabled, + bool source_file_target_option_enabled, + std::vector<std::string>& source_file_directories, + std::vector<std::string>& source_file_target_directories, + std::vector<cmMakefile*>& source_file_directory_makefiles) +{ + bool scope_options_valid = + SetPropertyCommand::HandleSourceFileDirectoryScopeValidation( + status, source_file_directory_option_enabled, + source_file_target_option_enabled, source_file_directories, + source_file_target_directories); + if (!scope_options_valid) { + return false; + } + + scope_options_valid = SetPropertyCommand::HandleSourceFileDirectoryScopes( + status, source_file_directories, source_file_target_directories, + source_file_directory_makefiles); + return scope_options_valid; +} + +std::string MakeSourceFilePathAbsoluteIfNeeded( + cmExecutionStatus& status, const std::string& source_file_path, + const bool needed) +{ + if (!needed) { + return source_file_path; + } + const std::string absolute_file_path = cmSystemTools::CollapseFullPath( + source_file_path, status.GetMakefile().GetCurrentSourceDirectory()); + return absolute_file_path; +} + +void MakeSourceFilePathsAbsoluteIfNeeded( + cmExecutionStatus& status, + std::vector<std::string>& source_files_absolute_paths, + std::vector<std::string>::const_iterator files_it_begin, + std::vector<std::string>::const_iterator files_it_end, const bool needed) +{ + + // Make the file paths absolute, so that relative source file paths are + // picked up relative to the command calling site, regardless of the + // directory scope. + std::vector<std::string>::difference_type num_files = + files_it_end - files_it_begin; + source_files_absolute_paths.reserve(num_files); + + if (!needed) { + source_files_absolute_paths.assign(files_it_begin, files_it_end); + return; + } + + for (; files_it_begin != files_it_end; ++files_it_begin) { + const std::string absolute_file_path = + MakeSourceFilePathAbsoluteIfNeeded(status, *files_it_begin, true); + source_files_absolute_paths.push_back(absolute_file_path); + } +} +} + bool cmSetPropertyCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -114,13 +258,20 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args, std::string propertyName; std::string propertyValue; + std::vector<std::string> source_file_directories; + std::vector<std::string> source_file_target_directories; + bool source_file_directory_option_enabled = false; + bool source_file_target_option_enabled = false; + // Parse the rest of the arguments up to the values. enum Doing { DoingNone, DoingNames, DoingProperty, - DoingValues + DoingValues, + DoingSourceDirectory, + DoingSourceTargetDirectory }; Doing doing = DoingNames; const char* sep = ""; @@ -137,8 +288,20 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args, appendMode = true; remove = false; appendAsString = true; + } else if (doing != DoingProperty && doing != DoingValues && + scope == cmProperty::SOURCE_FILE && arg == "DIRECTORY") { + doing = DoingSourceDirectory; + source_file_directory_option_enabled = true; + } else if (doing != DoingProperty && doing != DoingValues && + scope == cmProperty::SOURCE_FILE && arg == "TARGET_DIRECTORY") { + doing = DoingSourceTargetDirectory; + source_file_target_option_enabled = true; } else if (doing == DoingNames) { names.insert(arg); + } else if (doing == DoingSourceDirectory) { + source_file_directories.push_back(arg); + } else if (doing == DoingSourceTargetDirectory) { + source_file_target_directories.push_back(arg); } else if (doing == DoingProperty) { propertyName = arg; doing = DoingValues; @@ -159,6 +322,18 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args, return false; } + std::vector<cmMakefile*> source_file_directory_makefiles; + bool file_scopes_handled = + SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes( + status, source_file_directory_option_enabled, + source_file_target_option_enabled, source_file_directories, + source_file_target_directories, source_file_directory_makefiles); + if (!file_scopes_handled) { + return false; + } + bool source_file_paths_should_be_absolute = + source_file_directory_option_enabled || source_file_target_option_enabled; + // Dispatch property setting. switch (scope) { case cmProperty::GLOBAL: @@ -172,7 +347,9 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args, appendAsString, appendMode, remove); case cmProperty::SOURCE_FILE: return HandleSourceMode(status, names, propertyName, propertyValue, - appendAsString, appendMode, remove); + appendAsString, appendMode, remove, + source_file_directory_makefiles, + source_file_paths_should_be_absolute); case cmProperty::TEST: return HandleTestMode(status, names, propertyName, propertyValue, appendAsString, appendMode, remove); @@ -235,14 +412,8 @@ bool HandleDirectoryMode(cmExecutionStatus& status, if (!names.empty()) { // Construct the directory name. Interpret relative paths with // respect to the current directory. - std::string dir = *names.begin(); - if (!cmSystemTools::FileIsFullPath(dir)) { - dir = cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', - *names.begin()); - } - - // The local generators are associated with collapsed paths. - dir = cmSystemTools::CollapseFullPath(dir); + std::string dir = cmSystemTools::CollapseFullPath( + *names.begin(), status.GetMakefile().GetCurrentSourceDirectory()); mf = status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir); if (!mf) { @@ -307,7 +478,7 @@ bool HandleTarget(cmTarget* target, cmMakefile& makefile, if (remove) { target->SetProperty(propertyName, nullptr); } else { - target->SetProperty(propertyName, propertyValue.c_str()); + target->SetProperty(propertyName, propertyValue); } } @@ -321,21 +492,32 @@ bool HandleSourceMode(cmExecutionStatus& status, const std::set<std::string>& names, const std::string& propertyName, const std::string& propertyValue, bool appendAsString, - bool appendMode, bool remove) + bool appendMode, bool remove, + const std::vector<cmMakefile*>& directory_makefiles, + const bool source_file_paths_should_be_absolute) { - for (std::string const& name : names) { - // Get the source file. - if (cmSourceFile* sf = status.GetMakefile().GetOrCreateSource(name)) { - if (!HandleSource(sf, propertyName, propertyValue, appendAsString, - appendMode, remove)) { + std::vector<std::string> files_absolute; + std::vector<std::string> unique_files(names.begin(), names.end()); + SetPropertyCommand::MakeSourceFilePathsAbsoluteIfNeeded( + status, files_absolute, unique_files.begin(), unique_files.end(), + source_file_paths_should_be_absolute); + + for (const auto mf : directory_makefiles) { + for (std::string const& name : files_absolute) { + // Get the source file. + if (cmSourceFile* sf = mf->GetOrCreateSource(name)) { + if (!HandleSource(sf, propertyName, propertyValue, appendAsString, + appendMode, remove)) { + return false; + } + } else { + status.SetError(cmStrCat( + "given SOURCE name that could not be found or created: ", name)); return false; } - } else { - status.SetError(cmStrCat( - "given SOURCE name that could not be found or created: ", name)); - return false; } } + return true; } @@ -438,7 +620,7 @@ bool HandleCacheMode(cmExecutionStatus& status, for (std::string const& name : names) { // Get the source file. cmake* cm = status.GetMakefile().GetCMakeInstance(); - const char* existingValue = cm->GetState()->GetCacheEntryValue(name); + cmProp existingValue = cm->GetState()->GetCacheEntryValue(name); if (existingValue) { if (!HandleCacheEntry(name, status.GetMakefile(), propertyName, propertyValue, appendAsString, appendMode, @@ -460,16 +642,15 @@ bool HandleCacheEntry(std::string const& cacheKey, const cmMakefile& makefile, 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; @@ -505,13 +686,13 @@ bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile, 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/cmSetPropertyCommand.h b/Source/cmSetPropertyCommand.h index ec36f849e..af566a3a5 100644 --- a/Source/cmSetPropertyCommand.h +++ b/Source/cmSetPropertyCommand.h @@ -8,9 +8,38 @@ #include <string> #include <vector> +class cmMakefile; class cmExecutionStatus; bool cmSetPropertyCommand(std::vector<std::string> const& args, cmExecutionStatus& status); +namespace SetPropertyCommand { +bool HandleSourceFileDirectoryScopes( + cmExecutionStatus& status, std::vector<std::string>& source_file_directories, + std::vector<std::string>& source_file_target_directories, + std::vector<cmMakefile*>& directory_makefiles); + +bool HandleSourceFileDirectoryScopeValidation( + cmExecutionStatus& status, bool source_file_directory_option_enabled, + bool source_file_target_option_enabled, + std::vector<std::string>& source_file_directories, + std::vector<std::string>& source_file_target_directories); + +bool HandleAndValidateSourceFileDirectortoryScopes( + cmExecutionStatus& status, bool source_directories_option_encountered, + bool source_target_directories_option_encountered, + std::vector<std::string>& source_directories, + std::vector<std::string>& source_target_directories, + std::vector<cmMakefile*>& source_file_directory_makefiles); + +std::string MakeSourceFilePathAbsoluteIfNeeded( + cmExecutionStatus& status, const std::string& source_file_path, bool needed); +void MakeSourceFilePathsAbsoluteIfNeeded( + cmExecutionStatus& status, + std::vector<std::string>& source_files_absolute_paths, + std::vector<std::string>::const_iterator files_it_begin, + std::vector<std::string>::const_iterator files_it_end, bool needed); +} + #endif diff --git a/Source/cmSetSourceFilesPropertiesCommand.cxx b/Source/cmSetSourceFilesPropertiesCommand.cxx index 7ff604be0..c1b0c28db 100644 --- a/Source/cmSetSourceFilesPropertiesCommand.cxx +++ b/Source/cmSetSourceFilesPropertiesCommand.cxx @@ -2,17 +2,23 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmSetSourceFilesPropertiesCommand.h" +#include <algorithm> +#include <iterator> + +#include <cm/string_view> +#include <cmext/algorithm> + #include "cmExecutionStatus.h" #include "cmMakefile.h" +#include "cmSetPropertyCommand.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" -static bool RunCommand(cmMakefile* mf, - std::vector<std::string>::const_iterator filebeg, - std::vector<std::string>::const_iterator fileend, - std::vector<std::string>::const_iterator propbeg, - std::vector<std::string>::const_iterator propend, - std::string& errors); +static bool RunCommandForScope( + cmMakefile* mf, std::vector<std::string>::const_iterator file_begin, + std::vector<std::string>::const_iterator file_end, + std::vector<std::string>::const_iterator prop_begin, + std::vector<std::string>::const_iterator prop_end, std::string& errors); bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args, cmExecutionStatus& status) @@ -23,56 +29,106 @@ bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args, } // break the arguments into source file names and properties - int numFiles = 0; - std::vector<std::string>::const_iterator j; - j = args.begin(); // old style allows for specifier before PROPERTIES keyword - while (j != args.end() && *j != "ABSTRACT" && *j != "WRAP_EXCLUDE" && - *j != "GENERATED" && *j != "COMPILE_FLAGS" && - *j != "OBJECT_DEPENDS" && *j != "PROPERTIES") { - numFiles++; - ++j; + static const cm::string_view prop_names[] = { + "ABSTRACT", "GENERATED", "WRAP_EXCLUDE", "COMPILE_FLAGS", + "OBJECT_DEPENDS", "PROPERTIES", "DIRECTORY", "TARGET_DIRECTORY" + }; + + auto isAPropertyKeyword = + [](const std::vector<std::string>::const_iterator& arg_it) { + return std::any_of( + std::begin(prop_names), std::end(prop_names), + [&arg_it](cm::string_view prop_name) { return *arg_it == prop_name; }); + }; + + auto options_begin = std::find_first_of( + args.begin(), args.end(), std::begin(prop_names), std::end(prop_names)); + auto options_it = options_begin; + + // Handle directory options. + std::vector<std::string> source_file_directories; + std::vector<std::string> source_file_target_directories; + bool source_file_directory_option_enabled = false; + bool source_file_target_option_enabled = false; + std::vector<cmMakefile*> source_file_directory_makefiles; + + enum Doing + { + DoingNone, + DoingSourceDirectory, + DoingSourceTargetDirectory + }; + Doing doing = DoingNone; + for (; options_it != args.end(); ++options_it) { + if (*options_it == "DIRECTORY") { + doing = DoingSourceDirectory; + source_file_directory_option_enabled = true; + } else if (*options_it == "TARGET_DIRECTORY") { + doing = DoingSourceTargetDirectory; + source_file_target_option_enabled = true; + } else if (isAPropertyKeyword(options_it)) { + break; + } else if (doing == DoingSourceDirectory) { + source_file_directories.push_back(*options_it); + } else if (doing == DoingSourceTargetDirectory) { + source_file_target_directories.push_back(*options_it); + } else { + status.SetError( + cmStrCat("given invalid argument \"", *options_it, "\".")); + } + } + + const auto props_begin = options_it; + + bool file_scopes_handled = + SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes( + status, source_file_directory_option_enabled, + source_file_target_option_enabled, source_file_directories, + source_file_target_directories, source_file_directory_makefiles); + if (!file_scopes_handled) { + return false; } - cmMakefile& mf = status.GetMakefile(); + std::vector<std::string> files; + bool source_file_paths_should_be_absolute = + source_file_directory_option_enabled || source_file_target_option_enabled; + SetPropertyCommand::MakeSourceFilePathsAbsoluteIfNeeded( + status, files, args.begin(), options_begin, + source_file_paths_should_be_absolute); - // now call the worker function + // Now call the worker function for each directory scope represented by a + // cmMakefile instance. std::string errors; - bool ret = RunCommand(&mf, args.begin(), args.begin() + numFiles, - args.begin() + numFiles, args.end(), errors); - if (!ret) { - status.SetError(errors); + for (const auto mf : source_file_directory_makefiles) { + bool ret = RunCommandForScope(mf, files.begin(), files.end(), props_begin, + args.end(), errors); + if (!ret) { + status.SetError(errors); + return ret; + } } - return ret; + + return true; } -static bool RunCommand(cmMakefile* mf, - std::vector<std::string>::const_iterator filebeg, - std::vector<std::string>::const_iterator fileend, - std::vector<std::string>::const_iterator propbeg, - std::vector<std::string>::const_iterator propend, - std::string& errors) +static bool RunCommandForScope( + cmMakefile* mf, std::vector<std::string>::const_iterator file_begin, + std::vector<std::string>::const_iterator file_end, + std::vector<std::string>::const_iterator prop_begin, + std::vector<std::string>::const_iterator prop_end, std::string& errors) { std::vector<std::string> propertyPairs; - bool generated = false; - std::vector<std::string>::const_iterator j; // build the property pairs - for (j = propbeg; j != propend; ++j) { - // old style allows for specifier before PROPERTIES keyword - if (*j == "ABSTRACT") { - propertyPairs.emplace_back("ABSTRACT"); - propertyPairs.emplace_back("1"); - } else if (*j == "WRAP_EXCLUDE") { - propertyPairs.emplace_back("WRAP_EXCLUDE"); - propertyPairs.emplace_back("1"); - } else if (*j == "GENERATED") { - generated = true; - propertyPairs.emplace_back("GENERATED"); + for (auto j = prop_begin; j != prop_end; ++j) { + // consume old style options + if (*j == "ABSTRACT" || *j == "GENERATED" || *j == "WRAP_EXCLUDE") { + propertyPairs.emplace_back(*j); propertyPairs.emplace_back("1"); } else if (*j == "COMPILE_FLAGS") { propertyPairs.emplace_back("COMPILE_FLAGS"); ++j; - if (j == propend) { + if (j == prop_end) { errors = "called with incorrect number of arguments " "COMPILE_FLAGS with no flags"; return false; @@ -81,33 +137,22 @@ static bool RunCommand(cmMakefile* mf, } else if (*j == "OBJECT_DEPENDS") { propertyPairs.emplace_back("OBJECT_DEPENDS"); ++j; - if (j == propend) { + if (j == prop_end) { errors = "called with incorrect number of arguments " "OBJECT_DEPENDS with no dependencies"; return false; } propertyPairs.push_back(*j); } else if (*j == "PROPERTIES") { - // now loop through the rest of the arguments, new style - ++j; - while (j != propend) { - propertyPairs.push_back(*j); - if (*j == "GENERATED") { - ++j; - if (j != propend && cmIsOn(*j)) { - generated = true; - } - } else { - ++j; - } - if (j == propend) { - errors = "called with incorrect number of arguments."; - return false; - } - propertyPairs.push_back(*j); - ++j; + // PROPERTIES is followed by new style prop value pairs + cmStringRange newStyleProps{ j + 1, prop_end }; + if (newStyleProps.size() % 2 != 0) { + errors = "called with incorrect number of arguments."; + return false; } - // break out of the loop because j is already == end + // set newStyleProps as is. + cm::append(propertyPairs, newStyleProps); + // break out of the loop. break; } else { errors = "called with illegal arguments, maybe missing a " @@ -116,15 +161,13 @@ static bool RunCommand(cmMakefile* mf, } } - // now loop over all the files - for (j = filebeg; j != fileend; ++j) { + // loop over all the files + for (const std::string& sfname : cmStringRange{ file_begin, file_end }) { // get the source file - cmSourceFile* sf = mf->GetOrCreateSource(*j, generated); - if (sf) { - // now loop through all the props and set them - unsigned int k; - for (k = 0; k < propertyPairs.size(); k = k + 2) { - sf->SetProperty(propertyPairs[k], propertyPairs[k + 1].c_str()); + if (cmSourceFile* sf = mf->GetOrCreateSource(sfname)) { + // loop through the props and set them + for (auto k = propertyPairs.begin(); k != propertyPairs.end(); k += 2) { + sf->SetProperty(*k, (k + 1)->c_str()); } } } diff --git a/Source/cmSetTargetPropertiesCommand.cxx b/Source/cmSetTargetPropertiesCommand.cxx index cd0fa402a..bdc84af20 100644 --- a/Source/cmSetTargetPropertiesCommand.cxx +++ b/Source/cmSetTargetPropertiesCommand.cxx @@ -2,19 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmSetTargetPropertiesCommand.h" +#include <algorithm> #include <iterator> -#include <cmext/algorithm> - #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmTarget.h" -static bool SetOneTarget(const std::string& tname, - std::vector<std::string>& propertyPairs, - cmMakefile* mf); - bool cmSetTargetPropertiesCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -23,61 +18,38 @@ bool cmSetTargetPropertiesCommand(std::vector<std::string> const& args, return false; } - // first collect up the list of files - std::vector<std::string> propertyPairs; - int numFiles = 0; - for (auto j = args.begin(); j != args.end(); ++j) { - if (*j == "PROPERTIES") { - // now loop through the rest of the arguments, new style - ++j; - if (std::distance(j, args.end()) % 2 != 0) { - status.SetError("called with incorrect number of arguments."); - return false; - } - cm::append(propertyPairs, j, args.end()); - break; - } - numFiles++; + // first identify the properties arguments + auto propsIter = std::find(args.begin(), args.end(), "PROPERTIES"); + if (propsIter == args.end() || propsIter + 1 == args.end()) { + status.SetError("called with illegal arguments, maybe missing a " + "PROPERTIES specifier?"); + return false; } - if (propertyPairs.empty()) { - status.SetError("called with illegal arguments, maybe missing " - "a PROPERTIES specifier?"); + + if (std::distance(propsIter, args.end()) % 2 != 1) { + status.SetError("called with incorrect number of arguments."); return false; } cmMakefile& mf = status.GetMakefile(); - // now loop over all the targets - for (int i = 0; i < numFiles; ++i) { - if (mf.IsAlias(args[i])) { + // loop over all the targets + for (const std::string& tname : cmStringRange{ args.begin(), propsIter }) { + if (mf.IsAlias(tname)) { status.SetError("can not be used on an ALIAS target."); return false; } - bool ret = SetOneTarget(args[i], propertyPairs, &mf); - if (!ret) { + if (cmTarget* target = mf.FindTargetToUse(tname)) { + // loop through all the props and set them + for (auto k = propsIter + 1; k != args.end(); k += 2) { + target->SetProperty(*k, *(k + 1)); + target->CheckProperty(*k, &mf); + } + } else { status.SetError( - cmStrCat("Can not find target to add properties to: ", args[i])); + cmStrCat("Can not find target to add properties to: ", tname)); return false; } } return true; } - -static bool SetOneTarget(const std::string& tname, - std::vector<std::string>& propertyPairs, - cmMakefile* mf) -{ - if (cmTarget* target = mf->FindTargetToUse(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]); - target->CheckProperty(propertyPairs[k], mf); - } - } - // if file is not already in the makefile, then add it - else { - return false; - } - return true; -} diff --git a/Source/cmSetTestsPropertiesCommand.cxx b/Source/cmSetTestsPropertiesCommand.cxx index 2e7aecabc..c4bff76f6 100644 --- a/Source/cmSetTestsPropertiesCommand.cxx +++ b/Source/cmSetTestsPropertiesCommand.cxx @@ -2,19 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmSetTestsPropertiesCommand.h" +#include <algorithm> #include <iterator> -#include <cmext/algorithm> - #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmTest.h" -static bool SetOneTest(const std::string& tname, - std::vector<std::string>& propertyPairs, cmMakefile* mf, - std::string& errors); - bool cmSetTestsPropertiesCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -23,61 +18,33 @@ bool cmSetTestsPropertiesCommand(std::vector<std::string> const& args, return false; } - cmMakefile& mf = status.GetMakefile(); - - // first collect up the list of files - std::vector<std::string> propertyPairs; - int numFiles = 0; - std::vector<std::string>::const_iterator j; - for (j = args.begin(); j != args.end(); ++j) { - if (*j == "PROPERTIES") { - // now loop through the rest of the arguments, new style - ++j; - if (std::distance(j, args.end()) % 2 != 0) { - status.SetError("called with incorrect number of arguments."); - return false; - } - cm::append(propertyPairs, j, args.end()); - break; - } - numFiles++; - } - if (propertyPairs.empty()) { - status.SetError("called with illegal arguments, maybe " - "missing a PROPERTIES specifier?"); + // first identify the properties arguments + auto propsIter = std::find(args.begin(), args.end(), "PROPERTIES"); + if (propsIter == args.end() || propsIter + 1 == args.end()) { + status.SetError("called with illegal arguments, maybe missing a " + "PROPERTIES specifier?"); return false; } - // now loop over all the targets - int i; - for (i = 0; i < numFiles; ++i) { - std::string errors; - bool ret = SetOneTest(args[i], propertyPairs, &mf, errors); - if (!ret) { - status.SetError(errors); - return ret; - } + if (std::distance(propsIter, args.end()) % 2 != 1) { + status.SetError("called with incorrect number of arguments."); + return false; } - return true; -} - -static bool SetOneTest(const std::string& tname, - std::vector<std::string>& propertyPairs, cmMakefile* mf, - std::string& errors) -{ - if (cmTest* test = mf->GetTest(tname)) { - // now loop through all the props and set them - unsigned int k; - for (k = 0; k < propertyPairs.size(); k = k + 2) { - if (!propertyPairs[k].empty()) { - test->SetProperty(propertyPairs[k], propertyPairs[k + 1].c_str()); + // loop over all the tests + for (const std::string& tname : cmStringRange{ args.begin(), propsIter }) { + if (cmTest* test = status.GetMakefile().GetTest(tname)) { + // loop through all the props and set them + for (auto k = propsIter + 1; k != args.end(); k += 2) { + if (!k->empty()) { + test->SetProperty(*k, (k + 1)->c_str()); + } } + } else { + status.SetError( + cmStrCat("Can not find test to add properties to: ", tname)); + return false; } - } else { - errors = cmStrCat("Can not find test to add properties to: ", tname); - return false; } - return true; } diff --git a/Source/cmSiteNameCommand.cxx b/Source/cmSiteNameCommand.cxx index d47f121e0..b2d905e5b 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 fd9cacdbf..f5254392d 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -48,9 +48,9 @@ std::string cmSourceFile::GetObjectLibrary() const std::string const& cmSourceFile::GetOrDetermineLanguage() { // If the language was set explicitly by the user then use it. - if (const char* lang = this->GetProperty(propLANGUAGE)) { + if (cmProp lang = this->GetProperty(propLANGUAGE)) { // Assign to member in order to return a reference. - this->Language = lang; + this->Language = *lang; return this->Language; } @@ -81,8 +81,8 @@ std::string const& cmSourceFile::GetOrDetermineLanguage() std::string cmSourceFile::GetLanguage() const { // If the language was set explicitly by the user then use it. - if (const char* lang = this->GetProperty(propLANGUAGE)) { - return lang; + if (cmProp lang = this->GetProperty(propLANGUAGE)) { + return *lang; } // Use the language determined from the file extension. @@ -317,17 +317,18 @@ const char* cmSourceFile::GetPropertyForUser(const std::string& prop) } // Perform the normal property lookup. - return this->GetProperty(prop); + cmProp p = this->GetProperty(prop); + return p ? p->c_str() : nullptr; } -const char* cmSourceFile::GetProperty(const std::string& prop) const +cmProp cmSourceFile::GetProperty(const std::string& prop) const { // Check for computed properties. if (prop == propLOCATION) { if (this->FullPath.empty()) { return nullptr; } - return this->FullPath.c_str(); + return &this->FullPath; } // Check for the properties with backtraces. @@ -338,7 +339,7 @@ const char* cmSourceFile::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->IncludeDirectories, ";"); - return output.c_str(); + return &output; } if (prop == propCOMPILE_OPTIONS) { @@ -348,7 +349,7 @@ const char* cmSourceFile::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->CompileOptions, ";"); - return output.c_str(); + return &output; } if (prop == propCOMPILE_DEFINITIONS) { @@ -358,10 +359,10 @@ const char* cmSourceFile::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->CompileDefinitions, ";"); - return output.c_str(); + return &output; } - const char* retVal = this->Properties.GetPropertyValue(prop); + cmProp retVal = this->Properties.GetPropertyValue(prop); if (!retVal) { cmMakefile const* mf = this->Location.GetMakefile(); const bool chain = @@ -369,6 +370,7 @@ const char* cmSourceFile::GetProperty(const std::string& prop) const if (chain) { return mf->GetProperty(prop, chain); } + return nullptr; } return retVal; @@ -376,16 +378,17 @@ const char* cmSourceFile::GetProperty(const std::string& prop) const const char* cmSourceFile::GetSafeProperty(const std::string& prop) const { - const char* ret = this->GetProperty(prop); + cmProp ret = this->GetProperty(prop); if (!ret) { return ""; } - return ret; + return ret->c_str(); } bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const { - return cmIsOn(this->GetProperty(prop)); + cmProp p = this->GetProperty(prop); + return p && cmIsOn(*p); } void cmSourceFile::SetProperties(cmPropertyMap properties) diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h index e22829f18..e6690152e 100644 --- a/Source/cmSourceFile.h +++ b/Source/cmSourceFile.h @@ -11,6 +11,7 @@ #include "cmCustomCommand.h" #include "cmListFileCache.h" +#include "cmProperty.h" #include "cmPropertyMap.h" #include "cmSourceFileLocation.h" #include "cmSourceFileLocationKind.h" @@ -45,7 +46,7 @@ public: 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; + cmProp GetProperty(const std::string& prop) const; //! Always returns a valid pointer const char* GetSafeProperty(const std::string& prop) const; bool GetPropertyAsBool(const std::string& prop) const; @@ -157,7 +158,7 @@ private: "\\.(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)$" +#define CM_PCH_REGEX "cmake_pch(_[^.]+)?\\.(h|hxx)$" #define CM_RESOURCE_REGEX "\\.(pdf|plist|png|jpeg|jpg|storyboard|xcassets)$" diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx index 5f807b87f..e852c05ba 100644 --- a/Source/cmSourceFileLocation.cxx +++ b/Source/cmSourceFileLocation.cxx @@ -4,6 +4,8 @@ #include <cassert> +#include <cm/string_view> + #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -152,7 +154,7 @@ bool cmSourceFileLocation::MatchesAmbiguousExtension( // Only a fixed set of extensions will be tried to match a file on // disk. One of these must match if loc refers to this source file. - std::string const& ext = this->Name.substr(loc.Name.size() + 1); + auto ext = cm::string_view(this->Name).substr(loc.Name.size() + 1); cmMakefile const* mf = this->Makefile; auto cm = mf->GetCMakeInstance(); return cm->IsSourceExtension(ext) || cm->IsHeaderExtension(ext); diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx index 8c3ec9fec..155068cbe 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 581dc5dee..623cded23 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/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx index cc62952d8..bb75a14ba 100644 --- a/Source/cmSourceGroupCommand.cxx +++ b/Source/cmSourceGroupCommand.cxx @@ -7,7 +7,8 @@ #include <set> #include <utility> -#include "cmAlgorithms.h" +#include <cmext/algorithm> + #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmSourceGroup.h" @@ -30,18 +31,6 @@ std::vector<std::string> tokenizePath(const std::string& path) return cmTokenize(path, "\\/"); } -std::string getFullFilePath(const std::string& currentPath, - const std::string& path) -{ - std::string fullPath = path; - - if (!cmSystemTools::FileIsFullPath(path)) { - fullPath = cmStrCat(currentPath, '/', path); - } - - return cmSystemTools::CollapseFullPath(fullPath); -} - std::set<std::string> getSourceGroupFilesPaths( const std::string& root, const std::vector<std::string>& files) { @@ -124,7 +113,8 @@ bool addFilesToItsSourceGroups(const std::string& root, errorMsg = "Could not create source group for file: " + sgFilesPath; return false; } - const std::string fullPath = getFullFilePath(root, sgFilesPath); + const std::string fullPath = + cmSystemTools::CollapseFullPath(sgFilesPath, root); sg->AddGroupFile(fullPath); } } @@ -147,7 +137,7 @@ ExpectedOptions getExpectedOptions() bool isExpectedOption(const std::string& argument, const ExpectedOptions& expectedOptions) { - return cmContains(expectedOptions, argument); + return cm::contains(expectedOptions, argument); } void parseArguments(const std::vector<std::string>& args, @@ -255,10 +245,8 @@ bool cmSourceGroupCommand(std::vector<std::string> const& args, parsedArguments[kFilesOptionName]; for (auto const& filesArg : filesArguments) { std::string src = filesArg; - if (!cmSystemTools::FileIsFullPath(src)) { - src = cmStrCat(mf.GetCurrentSourceDirectory(), '/', filesArg); - } - src = cmSystemTools::CollapseFullPath(src); + src = + cmSystemTools::CollapseFullPath(src, mf.GetCurrentSourceDirectory()); sg->AddGroupFile(src); } } diff --git a/Source/cmStandardLexer.h b/Source/cmStandardLexer.h index 13f7622a7..cc67ac20e 100644 --- a/Source/cmStandardLexer.h +++ b/Source/cmStandardLexer.h @@ -3,6 +3,19 @@ #ifndef cmStandardLexer_h #define cmStandardLexer_h +#if !defined(_WIN32) && !defined(__sun) +/* POSIX APIs are needed */ +# define _POSIX_C_SOURCE 200809L +#endif +#if defined(__sun) && defined(__GNUC__) && !defined(__cplusplus) +/* C sources: for fileno and strdup */ +# define _XOPEN_SOURCE 600 +#endif +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) +/* For isascii */ +# define _XOPEN_SOURCE 700 +#endif + #include "cmsys/Configure.h" // IWYU pragma: keep /* Disable some warnings. */ @@ -50,7 +63,7 @@ #define YY_NO_UNPUT 1 #define ECHO -#include "cm_kwiml.h" +#include <cm3p/kwiml/int.h> typedef KWIML_INT_int8_t flex_int8_t; typedef KWIML_INT_uint8_t flex_uint8_t; typedef KWIML_INT_int16_t flex_int16_t; diff --git a/Source/cmState.cxx b/Source/cmState.cxx index 9fc76152f..0b6b40f4d 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -34,30 +34,44 @@ cmState::cmState() cmState::~cmState() = default; -const char* cmState::GetTargetTypeName(cmStateEnums::TargetType targetType) -{ +const std::string& cmState::GetTargetTypeName( + cmStateEnums::TargetType targetType) +{ +#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP + MAKE_STATIC_PROP(STATIC_LIBRARY); + MAKE_STATIC_PROP(MODULE_LIBRARY); + MAKE_STATIC_PROP(SHARED_LIBRARY); + MAKE_STATIC_PROP(OBJECT_LIBRARY); + MAKE_STATIC_PROP(EXECUTABLE); + MAKE_STATIC_PROP(UTILITY); + MAKE_STATIC_PROP(GLOBAL_TARGET); + MAKE_STATIC_PROP(INTERFACE_LIBRARY); + MAKE_STATIC_PROP(UNKNOWN_LIBRARY); + static const std::string propEmpty; +#undef MAKE_STATIC_PROP + switch (targetType) { case cmStateEnums::STATIC_LIBRARY: - return "STATIC_LIBRARY"; + return propSTATIC_LIBRARY; case cmStateEnums::MODULE_LIBRARY: - return "MODULE_LIBRARY"; + return propMODULE_LIBRARY; case cmStateEnums::SHARED_LIBRARY: - return "SHARED_LIBRARY"; + return propSHARED_LIBRARY; case cmStateEnums::OBJECT_LIBRARY: - return "OBJECT_LIBRARY"; + return propOBJECT_LIBRARY; case cmStateEnums::EXECUTABLE: - return "EXECUTABLE"; + return propEXECUTABLE; case cmStateEnums::UTILITY: - return "UTILITY"; + return propUTILITY; case cmStateEnums::GLOBAL_TARGET: - return "GLOBAL_TARGET"; + return propGLOBAL_TARGET; case cmStateEnums::INTERFACE_LIBRARY: - return "INTERFACE_LIBRARY"; + return propINTERFACE_LIBRARY; case cmStateEnums::UNKNOWN_LIBRARY: - return "UNKNOWN_LIBRARY"; + return propUNKNOWN_LIBRARY; } assert(false && "Unexpected target type"); - return nullptr; + return propEmpty; } static const std::array<std::string, 7> cmCacheEntryTypes = { @@ -123,36 +137,23 @@ bool cmState::DeleteCache(const std::string& path) std::vector<std::string> cmState::GetCacheEntryKeys() const { - std::vector<std::string> definitions; - definitions.reserve(this->CacheManager->GetSize()); - cmCacheManager::CacheIterator cit = this->CacheManager->GetCacheIterator(); - for (cit.Begin(); !cit.IsAtEnd(); cit.Next()) { - definitions.push_back(cit.GetName()); - } - return definitions; + return this->CacheManager->GetCacheEntryKeys(); } -const char* cmState::GetCacheEntryValue(std::string const& key) const +cmProp cmState::GetCacheEntryValue(std::string const& key) const { - cmCacheManager::CacheEntry* e = this->CacheManager->GetCacheEntry(key); - if (!e) { - return nullptr; - } - return e->Value.c_str(); + return this->CacheManager->GetCacheEntryValue(key); } std::string cmState::GetSafeCacheEntryValue(std::string const& key) const { - std::string retval; - auto val = this->GetCacheEntryValue(key); - if (val) { - retval = val; + if (cmProp val = this->GetCacheEntryValue(key)) { + return *val; } - return retval; + return std::string(); } -const std::string* cmState::GetInitializedCacheValue( - std::string const& key) const +cmProp cmState::GetInitializedCacheValue(std::string const& key) const { return this->CacheManager->GetInitializedCacheValue(key); } @@ -160,8 +161,7 @@ const std::string* cmState::GetInitializedCacheValue( cmStateEnums::CacheEntryType cmState::GetCacheEntryType( std::string const& key) const { - cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key); - return it.GetType(); + return this->CacheManager->GetCacheEntryType(key); } void cmState::SetCacheEntryValue(std::string const& key, @@ -174,40 +174,32 @@ void cmState::SetCacheEntryProperty(std::string const& key, std::string const& propertyName, std::string const& value) { - cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key); - it.SetProperty(propertyName, value.c_str()); + this->CacheManager->SetCacheEntryProperty(key, propertyName, value); } void cmState::SetCacheEntryBoolProperty(std::string const& key, std::string const& propertyName, bool value) { - cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key); - it.SetProperty(propertyName, value); + this->CacheManager->SetCacheEntryBoolProperty(key, propertyName, value); } std::vector<std::string> cmState::GetCacheEntryPropertyList( const std::string& key) { - cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key); - return it.GetPropertyList(); + return this->CacheManager->GetCacheEntryPropertyList(key); } -const char* cmState::GetCacheEntryProperty(std::string const& key, - std::string const& propertyName) +cmProp cmState::GetCacheEntryProperty(std::string const& key, + std::string const& propertyName) { - cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key); - if (!it.PropertyExists(propertyName)) { - return nullptr; - } - return it.GetProperty(propertyName); + return this->CacheManager->GetCacheEntryProperty(key, propertyName); } bool cmState::GetCacheEntryPropertyAsBool(std::string const& key, std::string const& propertyName) { - return this->CacheManager->GetCacheIterator(key).GetPropertyAsBool( - propertyName); + return this->CacheManager->GetCacheEntryPropertyAsBool(key, propertyName); } void cmState::AddCacheEntry(const std::string& key, const char* value, @@ -259,20 +251,19 @@ void cmState::AppendCacheEntryProperty(const std::string& key, const std::string& property, const std::string& value, bool asString) { - this->CacheManager->GetCacheIterator(key).AppendProperty(property, value, - asString); + this->CacheManager->AppendCacheEntryProperty(key, property, value, asString); } void cmState::RemoveCacheEntryProperty(std::string const& key, std::string const& propertyName) { - this->CacheManager->GetCacheIterator(key).SetProperty(propertyName, nullptr); + this->CacheManager->RemoveCacheEntryProperty(key, propertyName); } cmStateSnapshot cmState::Reset() { this->GlobalProperties.Clear(); - this->PropertyDefinitions.clear(); + this->PropertyDefinitions = {}; this->GlobVerificationManager->Reset(); cmStateDetail::PositionType pos = this->SnapshotData.Truncate(); @@ -335,42 +326,26 @@ cmStateSnapshot cmState::Reset() void cmState::DefineProperty(const std::string& name, cmProperty::ScopeType scope, - const char* ShortDescription, - const char* FullDescription, bool chained) + const std::string& ShortDescription, + const std::string& FullDescription, bool chained) { - this->PropertyDefinitions[scope].DefineProperty( - name, scope, ShortDescription, FullDescription, chained); + this->PropertyDefinitions.DefineProperty(name, scope, ShortDescription, + FullDescription, chained); } cmPropertyDefinition const* cmState::GetPropertyDefinition( const std::string& name, cmProperty::ScopeType scope) const { - if (this->IsPropertyDefined(name, scope)) { - cmPropertyDefinitionMap const& defs = - this->PropertyDefinitions.find(scope)->second; - return &defs.find(name)->second; - } - return nullptr; -} - -bool cmState::IsPropertyDefined(const std::string& name, - cmProperty::ScopeType scope) const -{ - auto it = this->PropertyDefinitions.find(scope); - if (it == this->PropertyDefinitions.end()) { - return false; - } - return it->second.IsPropertyDefined(name); + return this->PropertyDefinitions.GetPropertyDefinition(name, scope); } bool cmState::IsPropertyChained(const std::string& name, cmProperty::ScopeType scope) const { - auto it = this->PropertyDefinitions.find(scope); - if (it == this->PropertyDefinitions.end()) { - return false; + if (auto def = this->GetPropertyDefinition(name, scope)) { + return def->IsChained(); } - return it->second.IsPropertyChained(name); + return false; } void cmState::SetLanguageEnabled(std::string const& l) @@ -573,7 +548,7 @@ void cmState::AppendGlobalProperty(const std::string& prop, this->GlobalProperties.AppendProperty(prop, value, asString); } -const char* cmState::GetGlobalProperty(const std::string& prop) +cmProp cmState::GetGlobalProperty(const std::string& prop) { if (prop == "CACHE_VARIABLES") { std::vector<std::string> cacheKeys = this->GetCacheEntryKeys(); @@ -597,31 +572,49 @@ const char* cmState::GetGlobalProperty(const std::string& prop) } #define STRING_LIST_ELEMENT(F) ";" #F if (prop == "CMAKE_C_KNOWN_FEATURES") { - return &FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT)[1]; + static const std::string s_out( + &FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT)[1]); + return &s_out; } if (prop == "CMAKE_C90_KNOWN_FEATURES") { - return &FOR_EACH_C90_FEATURE(STRING_LIST_ELEMENT)[1]; + static const std::string s_out( + &FOR_EACH_C90_FEATURE(STRING_LIST_ELEMENT)[1]); + return &s_out; } if (prop == "CMAKE_C99_KNOWN_FEATURES") { - return &FOR_EACH_C99_FEATURE(STRING_LIST_ELEMENT)[1]; + static const std::string s_out( + &FOR_EACH_C99_FEATURE(STRING_LIST_ELEMENT)[1]); + return &s_out; } if (prop == "CMAKE_C11_KNOWN_FEATURES") { - return &FOR_EACH_C11_FEATURE(STRING_LIST_ELEMENT)[1]; + static const std::string s_out( + &FOR_EACH_C11_FEATURE(STRING_LIST_ELEMENT)[1]); + return &s_out; } if (prop == "CMAKE_CXX_KNOWN_FEATURES") { - return &FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT)[1]; + static const std::string s_out( + &FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT)[1]); + return &s_out; } if (prop == "CMAKE_CXX98_KNOWN_FEATURES") { - return &FOR_EACH_CXX98_FEATURE(STRING_LIST_ELEMENT)[1]; + static const std::string s_out( + &FOR_EACH_CXX98_FEATURE(STRING_LIST_ELEMENT)[1]); + return &s_out; } if (prop == "CMAKE_CXX11_KNOWN_FEATURES") { - return &FOR_EACH_CXX11_FEATURE(STRING_LIST_ELEMENT)[1]; + static const std::string s_out( + &FOR_EACH_CXX11_FEATURE(STRING_LIST_ELEMENT)[1]); + return &s_out; } if (prop == "CMAKE_CXX14_KNOWN_FEATURES") { - return &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1]; + static const std::string s_out( + &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1]); + return &s_out; } if (prop == "CMAKE_CUDA_KNOWN_FEATURES") { - return &FOR_EACH_CUDA_FEATURE(STRING_LIST_ELEMENT)[1]; + static const std::string s_out( + &FOR_EACH_CUDA_FEATURE(STRING_LIST_ELEMENT)[1]); + return &s_out; } #undef STRING_LIST_ELEMENT @@ -630,7 +623,8 @@ const char* cmState::GetGlobalProperty(const std::string& prop) bool cmState::GetGlobalPropertyAsBool(const std::string& prop) { - return cmIsOn(this->GetGlobalProperty(prop)); + cmProp p = this->GetGlobalProperty(prop); + return p && cmIsOn(*p); } void cmState::SetSourceDirectory(std::string const& sourceDirectory) diff --git a/Source/cmState.h b/Source/cmState.h index 6ee2b0c80..885496a92 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -17,7 +17,7 @@ #include "cmListFileCache.h" #include "cmPolicies.h" #include "cmProperty.h" -#include "cmPropertyDefinitionMap.h" +#include "cmPropertyDefinition.h" #include "cmPropertyMap.h" #include "cmStatePrivate.h" #include "cmStateTypes.h" @@ -25,7 +25,6 @@ class cmCacheManager; class cmCommand; class cmGlobVerificationManager; -class cmPropertyDefinition; class cmStateSnapshot; class cmMessenger; class cmExecutionStatus; @@ -51,7 +50,8 @@ public: CPack, }; - static const char* GetTargetTypeName(cmStateEnums::TargetType targetType); + static const std::string& GetTargetTypeName( + cmStateEnums::TargetType targetType); cmStateSnapshot CreateBaseSnapshot(); cmStateSnapshot CreateBuildsystemDirectorySnapshot( @@ -87,12 +87,11 @@ public: bool DeleteCache(const std::string& path); std::vector<std::string> GetCacheEntryKeys() const; - const char* GetCacheEntryValue(std::string const& key) const; + cmProp GetCacheEntryValue(std::string const& key) const; std::string GetSafeCacheEntryValue(std::string const& key) const; - const std::string* GetInitializedCacheValue(std::string const& key) const; + cmProp GetInitializedCacheValue(std::string const& key) const; cmStateEnums::CacheEntryType GetCacheEntryType(std::string const& key) const; void SetCacheEntryValue(std::string const& key, std::string const& value); - void SetCacheValue(std::string const& key, std::string const& value); void RemoveCacheEntry(std::string const& key); @@ -102,8 +101,8 @@ public: void SetCacheEntryBoolProperty(std::string const& key, std::string const& propertyName, bool value); std::vector<std::string> GetCacheEntryPropertyList(std::string const& key); - const char* GetCacheEntryProperty(std::string const& key, - std::string const& propertyName); + cmProp GetCacheEntryProperty(std::string const& key, + std::string const& propertyName); bool GetCacheEntryPropertyAsBool(std::string const& key, std::string const& propertyName); void AppendCacheEntryProperty(std::string const& key, @@ -121,16 +120,13 @@ public: cmStateSnapshot Reset(); // Define a property void DefineProperty(const std::string& name, cmProperty::ScopeType scope, - const char* ShortDescription, - const char* FullDescription, bool chain = false); + const std::string& ShortDescription, + const std::string& FullDescription, bool chain = false); // get property definition cmPropertyDefinition const* GetPropertyDefinition( const std::string& name, cmProperty::ScopeType scope) const; - // Is a property defined? - bool IsPropertyDefined(const std::string& name, - cmProperty::ScopeType scope) const; bool IsPropertyChained(const std::string& name, cmProperty::ScopeType scope) const; @@ -171,7 +167,7 @@ public: void SetGlobalProperty(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); + cmProp GetGlobalProperty(const std::string& prop); bool GetGlobalPropertyAsBool(const std::string& prop); std::string const& GetSourceDirectory() const; @@ -222,7 +218,7 @@ private: const std::string& variable, cmListFileBacktrace const& bt); - std::map<cmProperty::ScopeType, cmPropertyDefinitionMap> PropertyDefinitions; + cmPropertyDefinitionMap PropertyDefinitions; std::vector<std::string> EnabledLanguages; std::map<std::string, Command> BuiltinCommands; std::map<std::string, Command> ScriptedCommands; diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx index 4f003ed8f..a4fe66304 100644 --- a/Source/cmStateDirectory.cxx +++ b/Source/cmStateDirectory.cxx @@ -548,32 +548,31 @@ void cmStateDirectory::AppendProperty(const std::string& prop, this->DirectoryState->Properties.AppendProperty(prop, value, asString); } -const char* cmStateDirectory::GetProperty(const std::string& prop) const +cmProp cmStateDirectory::GetProperty(const std::string& prop) const { const bool chain = this->Snapshot_.State->IsPropertyChained(prop, cmProperty::DIRECTORY); return this->GetProperty(prop, chain); } -const char* cmStateDirectory::GetProperty(const std::string& prop, - bool chain) const +cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const { static std::string output; output.clear(); if (prop == "PARENT_DIRECTORY") { cmStateSnapshot parent = this->Snapshot_.GetBuildsystemDirectoryParent(); if (parent.IsValid()) { - return parent.GetDirectory().GetCurrentSource().c_str(); + return &parent.GetDirectory().GetCurrentSource(); } - return ""; + return &output; } if (prop == kBINARY_DIR) { output = this->GetCurrentBinary(); - return output.c_str(); + return &output; } if (prop == kSOURCE_DIR) { output = this->GetCurrentSource(); - return output.c_str(); + return &output; } if (prop == kSUBDIRECTORIES) { std::vector<std::string> child_dirs; @@ -584,11 +583,11 @@ const char* cmStateDirectory::GetProperty(const std::string& prop, child_dirs.push_back(ci.GetDirectory().GetCurrentSource()); } output = cmJoin(child_dirs, ";"); - return output.c_str(); + return &output; } if (prop == kBUILDSYSTEM_TARGETS) { output = cmJoin(this->DirectoryState->NormalTargetNames, ";"); - return output.c_str(); + return &output; } if (prop == "LISTFILE_STACK") { @@ -600,41 +599,41 @@ const char* cmStateDirectory::GetProperty(const std::string& prop, } std::reverse(listFiles.begin(), listFiles.end()); output = cmJoin(listFiles, ";"); - return output.c_str(); + return &output; } if (prop == "CACHE_VARIABLES") { output = cmJoin(this->Snapshot_.State->GetCacheEntryKeys(), ";"); - return output.c_str(); + return &output; } if (prop == "VARIABLES") { std::vector<std::string> res = this->Snapshot_.ClosureKeys(); cm::append(res, this->Snapshot_.State->GetCacheEntryKeys()); std::sort(res.begin(), res.end()); output = cmJoin(res, ";"); - return output.c_str(); + return &output; } if (prop == "INCLUDE_DIRECTORIES") { output = cmJoin(this->GetIncludeDirectoriesEntries(), ";"); - return output.c_str(); + return &output; } if (prop == "COMPILE_OPTIONS") { output = cmJoin(this->GetCompileOptionsEntries(), ";"); - return output.c_str(); + return &output; } if (prop == "COMPILE_DEFINITIONS") { output = cmJoin(this->GetCompileDefinitionsEntries(), ";"); - return output.c_str(); + return &output; } if (prop == "LINK_OPTIONS") { output = cmJoin(this->GetLinkOptionsEntries(), ";"); - return output.c_str(); + return &output; } if (prop == "LINK_DIRECTORIES") { output = cmJoin(this->GetLinkDirectoriesEntries(), ";"); - return output.c_str(); + return &output; } - const char* retVal = this->DirectoryState->Properties.GetPropertyValue(prop); + cmProp retVal = this->DirectoryState->Properties.GetPropertyValue(prop); if (!retVal && chain) { cmStateSnapshot parentSnapshot = this->Snapshot_.GetBuildsystemDirectoryParent(); @@ -649,7 +648,8 @@ const char* cmStateDirectory::GetProperty(const std::string& prop, bool cmStateDirectory::GetPropertyAsBool(const std::string& prop) const { - return cmIsOn(this->GetProperty(prop)); + cmProp p = this->GetProperty(prop); + return p && cmIsOn(*p); } std::vector<std::string> cmStateDirectory::GetPropertyKeys() const diff --git a/Source/cmStateDirectory.h b/Source/cmStateDirectory.h index 53a2d546d..765af6f4e 100644 --- a/Source/cmStateDirectory.h +++ b/Source/cmStateDirectory.h @@ -12,6 +12,7 @@ #include "cmAlgorithms.h" #include "cmLinkedTree.h" #include "cmListFileCache.h" +#include "cmProperty.h" #include "cmStatePrivate.h" #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" @@ -86,8 +87,8 @@ public: cmListFileBacktrace const& lfbt); 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; + cmProp GetProperty(const std::string& prop) const; + cmProp GetProperty(const std::string& prop, bool chain) const; bool GetPropertyAsBool(const std::string& prop) const; std::vector<std::string> GetPropertyKeys() const; diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx index 832e74ec7..c22343185 100644 --- a/Source/cmStateSnapshot.cxx +++ b/Source/cmStateSnapshot.cxx @@ -11,6 +11,7 @@ #include "cmDefinitions.h" #include "cmListFileCache.h" +#include "cmProperty.h" #include "cmPropertyMap.h" #include "cmState.h" #include "cmStateDirectory.h" @@ -411,11 +412,12 @@ void cmStateSnapshot::InitializeFromParent() this->Position->BuildSystemDirectory->LinkDirectoriesBacktraces, this->Position->LinkDirectoriesPosition); - const char* include_regex = + cmProp include_regex = parent->BuildSystemDirectory->Properties.GetPropertyValue( "INCLUDE_REGULAR_EXPRESSION"); this->Position->BuildSystemDirectory->Properties.SetProperty( - "INCLUDE_REGULAR_EXPRESSION", include_regex); + "INCLUDE_REGULAR_EXPRESSION", + include_regex ? include_regex->c_str() : nullptr); } cmState* cmStateSnapshot::GetState() const diff --git a/Source/cmString.hxx b/Source/cmString.hxx index 9e9198650..87bfdffcf 100644 --- a/Source/cmString.hxx +++ b/Source/cmString.hxx @@ -16,8 +16,7 @@ #include <utility> #include <cm/string_view> - -#include "cm_static_string_view.hxx" +#include <cmext/string_view> namespace cm { diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx index bb6dcd734..71d28a49d 100644 --- a/Source/cmStringAlgorithms.cxx +++ b/Source/cmStringAlgorithms.cxx @@ -4,7 +4,7 @@ #include <algorithm> #include <cerrno> -#include <cstddef> +#include <cstddef> // IWYU pragma: keep #include <cstdio> #include <cstdlib> diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h index 0e405dea6..a5ecca758 100644 --- a/Source/cmStringAlgorithms.h +++ b/Source/cmStringAlgorithms.h @@ -87,7 +87,7 @@ void cmExpandLists(InputIt first, InputIt last, std::vector<std::string>& argsOut) { for (; first != last; ++first) { - ExpandList(*first, argsOut); + cmExpandList(*first, argsOut); } } diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 9212195f5..a7c21ccf0 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -11,11 +11,10 @@ #include <memory> #include <cm/iterator> +#include <cmext/string_view> #include "cmsys/RegularExpression.hxx" -#include "cm_static_string_view.hxx" - #include "cmCryptoHash.h" #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" @@ -124,6 +123,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 +956,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/cmSubcommandTable.h b/Source/cmSubcommandTable.h index 65eb8c794..7deaaed69 100644 --- a/Source/cmSubcommandTable.h +++ b/Source/cmSubcommandTable.h @@ -11,8 +11,7 @@ #include <vector> #include <cm/string_view> - -#include "cm_static_string_view.hxx" +#include <cmext/string_view> class cmExecutionStatus; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 9127c50e9..1e78d3693 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1,10 +1,20 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ + +#if !defined(_WIN32) && !defined(__sun) +// POSIX APIs are needed +# define _POSIX_C_SOURCE 200809L +#endif +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) +// For isascii +# define _XOPEN_SOURCE 700 +#endif + #include "cmSystemTools.h" #include <cmext/algorithm> -#include "cm_uv.h" +#include <cm3p/uv.h> #include "cmDuration.h" #include "cmProcessOutput.h" @@ -12,7 +22,8 @@ #include "cmStringAlgorithms.h" #if !defined(CMAKE_BOOTSTRAP) -# include "cm_libarchive.h" +# include <cm3p/archive.h> +# include <cm3p/archive_entry.h> # include "cmArchiveWrite.h" # include "cmLocale.h" @@ -25,6 +36,9 @@ #endif #if !defined(CMAKE_BOOTSTRAP) +# if defined(_WIN32) +# include <cm/memory> +# endif # include "cmCryptoHash.h" #endif @@ -809,7 +823,9 @@ void cmSystemTools::InitializeLibUV() // Perform libuv one-time initialization now, and then un-do its // global _fmode setting so that using libuv does not change the // default file text/binary mode. See libuv issue 840. - uv_loop_close(uv_default_loop()); + if (uv_loop_t* loop = uv_default_loop()) { + uv_loop_close(loop); + } # ifdef _MSC_VER _set_fmode(_O_TEXT); # else @@ -908,7 +924,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; @@ -920,12 +935,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)) { @@ -961,7 +976,6 @@ std::string cmSystemTools::ComputeCertificateThumbprint( } } } - delete[] certData; } } CloseHandle(certFile); @@ -1054,8 +1068,7 @@ bool cmSystemTools::SimpleGlob(const std::string& glob, if (type < 0 && !cmSystemTools::FileIsDirectory(fname)) { continue; } - if (sfname.size() >= ppath.size() && - sfname.substr(0, ppath.size()) == ppath) { + if (cmHasPrefix(sfname, ppath)) { files.push_back(fname); res = true; } @@ -1311,6 +1324,7 @@ bool cmSystemTools::CreateTar(const std::string& outFileName, cmArchiveWrite a(fout, compress, format.empty() ? "paxr" : format); + a.Open(); a.SetMTime(mtime); a.SetVerbose(verbose); bool tarCreatedSuccessfully = true; @@ -2068,6 +2082,12 @@ std::string const& cmSystemTools::GetCMakeRoot() return cmSystemToolsCMakeRoot; } +std::string cmSystemTools::GetCurrentWorkingDirectory() +{ + return cmSystemTools::CollapseFullPath( + cmsys::SystemTools::GetCurrentWorkingDirectory()); +} + void cmSystemTools::MakefileColorEcho(int color, const char* message, bool newline, bool enabled) { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index ee149a029..b886c58dd 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -390,6 +390,9 @@ public: static std::string const& GetCMClDepsCommand(); static std::string const& GetCMakeRoot(); + /** Get the CWD mapped through the KWSys translation map. */ + static std::string GetCurrentWorkingDirectory(); + /** Echo a message in color using KWSys's Terminal cprintf. */ static void MakefileColorEcho(int color, const char* message, bool newLine, bool enabled); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 1ad9fd1a1..36e1ad5fd 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -78,7 +78,7 @@ const std::string& cmTargetPropertyComputer::ComputeLocation<cmTarget>( } template <> -const char* cmTargetPropertyComputer::GetSources<cmTarget>( +cmProp cmTargetPropertyComputer::GetSources<cmTarget>( cmTarget const* tgt, cmMessenger* messenger, cmListFileBacktrace const& context) { @@ -156,7 +156,7 @@ const char* cmTargetPropertyComputer::GetSources<cmTarget>( } static std::string srcs; srcs = ss.str(); - return srcs.c_str(); + return &srcs; } class cmTargetInternals @@ -215,7 +215,7 @@ public: }; cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, - Visibility vis, cmMakefile* mf, bool perConfig) + Visibility vis, cmMakefile* mf, PerConfig perConfig) : impl(cm::make_unique<cmTargetInternals>()) { assert(mf); @@ -231,7 +231,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, (vis == VisibilityImported || vis == VisibilityImportedGlobally); impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally; impl->BuildInterfaceIncludesAppended = false; - impl->PerConfig = perConfig; + impl->PerConfig = (perConfig == PerConfig::Yes); // Check whether this is a DLL platform. impl->IsDLLPlatform = @@ -303,9 +303,11 @@ 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"); + initProp("Fortran_PREPROCESS"); initProp("GNUtoMS"); initProp("OSX_ARCHITECTURES"); initProp("IOS_INSTALL_COMBINED"); @@ -362,6 +364,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("CUDA_SEPARABLE_COMPILATION"); initProp("CUDA_RESOLVE_DEVICE_SYMBOLS"); initProp("CUDA_RUNTIME_LIBRARY"); + initProp("CUDA_ARCHITECTURES"); initProp("LINK_SEARCH_START_STATIC"); initProp("LINK_SEARCH_END_STATIC"); initProp("Swift_LANGUAGE_VERSION"); @@ -370,6 +373,8 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("DISABLE_PRECOMPILE_HEADERS"); initProp("UNITY_BUILD"); initPropValue("UNITY_BUILD_BATCH_SIZE", "8"); + initPropValue("UNITY_BUILD_MODE", "BATCH"); + initPropValue("PCH_WARN_INVALID", "ON"); #ifdef __APPLE__ if (this->GetGlobalGenerator()->IsXcode()) { initProp("XCODE_SCHEME_ADDRESS_SANITIZER"); @@ -438,6 +443,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); + } } } @@ -521,7 +533,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("JOB_POOL_PRECOMPILE_HEADER"); } - if (impl->TargetType <= cmStateEnums::UTILITY) { + if (impl->TargetType <= cmStateEnums::GLOBAL_TARGET) { initProp("DOTNET_TARGET_FRAMEWORK"); initProp("DOTNET_TARGET_FRAMEWORK_VERSION"); } @@ -883,7 +895,7 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const cmListFileContext lfc = cmd.second; lfc.FilePath = cmDir.ConvertToRelPathIfNotContained( impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath); - s << " * " << lfc << std::endl; + s << " * " << lfc << '\n'; } } } @@ -1002,7 +1014,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); } } @@ -1295,8 +1307,8 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) reusedTarget->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY", cmStrCat(reusedFrom, ".dir/")); - this->SetProperty("COMPILE_PDB_NAME", - reusedTarget->GetProperty("COMPILE_PDB_NAME")); + cmProp tmp = reusedTarget->GetProperty("COMPILE_PDB_NAME"); + this->SetProperty("COMPILE_PDB_NAME", tmp ? tmp->c_str() : nullptr); this->AddUtility(reusedFrom, false, impl->Makefile); } else { impl->Properties.SetProperty(prop, value); @@ -1500,7 +1512,7 @@ void cmTarget::InsertPrecompileHeader(std::string const& entry, } static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop, - const char* value, + const std::string& value, cmMakefile* context, bool imported) { @@ -1538,7 +1550,7 @@ static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop, context->IssueMessage(MessageType::FATAL_ERROR, e.str()); } -static void cmTargetCheckINTERFACE_LINK_LIBRARIES(const char* value, +static void cmTargetCheckINTERFACE_LINK_LIBRARIES(const std::string& value, cmMakefile* context) { // Look for link-type keywords in the value. @@ -1583,18 +1595,18 @@ void cmTarget::CheckProperty(const std::string& prop, { // Certain properties need checking. if (cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES")) { - if (const char* value = this->GetProperty(prop)) { - cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, value, context, false); + if (cmProp value = this->GetProperty(prop)) { + cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, *value, context, false); } } if (cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES")) { - if (const char* value = this->GetProperty(prop)) { - cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, value, context, true); + if (cmProp value = this->GetProperty(prop)) { + cmTargetCheckLINK_INTERFACE_LIBRARIES(prop, *value, context, true); } } if (prop == "INTERFACE_LINK_LIBRARIES") { - if (const char* value = this->GetProperty(prop)) { - cmTargetCheckINTERFACE_LINK_LIBRARIES(value, context); + if (cmProp value = this->GetProperty(prop)) { + cmTargetCheckINTERFACE_LINK_LIBRARIES(*value, context); } } if (prop == "IMPORTED_GLOBAL") { @@ -1604,14 +1616,14 @@ void cmTarget::CheckProperty(const std::string& prop, } } -const char* cmTarget::GetComputedProperty( - const std::string& prop, cmMessenger* messenger, - cmListFileBacktrace const& context) const +cmProp cmTarget::GetComputedProperty(const std::string& prop, + cmMessenger* messenger, + cmListFileBacktrace const& context) const { return cmTargetPropertyComputer::GetProperty(this, prop, messenger, context); } -const char* cmTarget::GetProperty(const std::string& prop) const +cmProp cmTarget::GetProperty(const std::string& prop) const { #define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP MAKE_STATIC_PROP(LINK_LIBRARIES); @@ -1630,6 +1642,8 @@ const char* cmTarget::GetProperty(const std::string& prop) const MAKE_STATIC_PROP(BINARY_DIR); MAKE_STATIC_PROP(SOURCE_DIR); MAKE_STATIC_PROP(SOURCES); + MAKE_STATIC_PROP(FALSE); + MAKE_STATIC_PROP(TRUE); #undef MAKE_STATIC_PROP static std::unordered_set<std::string> const specialProps{ propLINK_LIBRARIES, @@ -1657,11 +1671,11 @@ const char* cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(impl->LinkImplementationPropertyEntries, ";"); - return output.c_str(); + return &output; } // the type property returns what type the target is if (prop == propTYPE) { - return cmState::GetTargetTypeName(this->GetType()); + return &cmState::GetTargetTypeName(this->GetType()); } if (prop == propINCLUDE_DIRECTORIES) { if (impl->IncludeDirectoriesEntries.empty()) { @@ -1670,7 +1684,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(impl->IncludeDirectoriesEntries, ";"); - return output.c_str(); + return &output; } if (prop == propCOMPILE_FEATURES) { if (impl->CompileFeaturesEntries.empty()) { @@ -1679,7 +1693,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(impl->CompileFeaturesEntries, ";"); - return output.c_str(); + return &output; } if (prop == propCOMPILE_OPTIONS) { if (impl->CompileOptionsEntries.empty()) { @@ -1688,7 +1702,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(impl->CompileOptionsEntries, ";"); - return output.c_str(); + return &output; } if (prop == propCOMPILE_DEFINITIONS) { if (impl->CompileDefinitionsEntries.empty()) { @@ -1697,7 +1711,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(impl->CompileDefinitionsEntries, ";"); - return output.c_str(); + return &output; } if (prop == propLINK_OPTIONS) { if (impl->LinkOptionsEntries.empty()) { @@ -1706,7 +1720,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(impl->LinkOptionsEntries, ";"); - return output.c_str(); + return &output; } if (prop == propLINK_DIRECTORIES) { if (impl->LinkDirectoriesEntries.empty()) { @@ -1716,7 +1730,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(impl->LinkDirectoriesEntries, ";"); - return output.c_str(); + return &output; } if (prop == propMANUALLY_ADDED_DEPENDENCIES) { if (impl->Utilities.empty()) { @@ -1732,7 +1746,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const return item.Value.first; }); output = cmJoin(utilities, ";"); - return output.c_str(); + return &output; } if (prop == propPRECOMPILE_HEADERS) { if (impl->PrecompileHeadersEntries.empty()) { @@ -1741,32 +1755,30 @@ const char* cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(impl->PrecompileHeadersEntries, ";"); - return output.c_str(); + return &output; } if (prop == propIMPORTED) { - return this->IsImported() ? "TRUE" : "FALSE"; + return this->IsImported() ? &propTRUE : &propFALSE; } if (prop == propIMPORTED_GLOBAL) { - return this->IsImportedGloballyVisible() ? "TRUE" : "FALSE"; + return this->IsImportedGloballyVisible() ? &propTRUE : &propFALSE; } if (prop == propNAME) { - return this->GetName().c_str(); + return &this->GetName(); } if (prop == propBINARY_DIR) { - return impl->Makefile->GetStateSnapshot() - .GetDirectory() - .GetCurrentBinary() - .c_str(); + return &impl->Makefile->GetStateSnapshot() + .GetDirectory() + .GetCurrentBinary(); } if (prop == propSOURCE_DIR) { - return impl->Makefile->GetStateSnapshot() - .GetDirectory() - .GetCurrentSource() - .c_str(); + return &impl->Makefile->GetStateSnapshot() + .GetDirectory() + .GetCurrentSource(); } } - const char* retVal = impl->Properties.GetPropertyValue(prop); + cmProp retVal = impl->Properties.GetPropertyValue(prop); if (!retVal) { const bool chain = impl->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TARGET); @@ -1774,22 +1786,26 @@ const char* cmTarget::GetProperty(const std::string& prop) const return impl->Makefile->GetStateSnapshot().GetDirectory().GetProperty( prop, chain); } + return nullptr; } return retVal; } -const char* cmTarget::GetSafeProperty(const std::string& prop) const +std::string const& cmTarget::GetSafeProperty(std::string const& prop) const { - const char* ret = this->GetProperty(prop); - if (!ret) { - return ""; + cmProp ret = this->GetProperty(prop); + if (ret) { + return *ret; } - return ret; + + static std::string const s_empty; + return s_empty; } bool cmTarget::GetPropertyAsBool(const std::string& prop) const { - return cmIsOn(this->GetProperty(prop)); + cmProp p = this->GetProperty(prop); + return p && cmIsOn(*p); } cmPropertyMap const& cmTarget::GetProperties() const @@ -1918,38 +1934,37 @@ std::string cmTarget::ImportedGetFullPath( std::string result; - const char* loc = nullptr; - const char* imp = nullptr; + cmProp loc = nullptr; + cmProp imp = nullptr; std::string suffix; if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && - this->GetMappedConfig(desired_config, &loc, &imp, suffix)) { + this->GetMappedConfig(desired_config, loc, imp, suffix)) { switch (artifact) { case cmStateEnums::RuntimeBinaryArtifact: if (loc) { - result = loc; + result = *loc; } else { std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix); - if (const char* config_location = this->GetProperty(impProp)) { - result = config_location; - } else if (const char* location = + if (cmProp config_location = this->GetProperty(impProp)) { + result = *config_location; + } else if (cmProp location = this->GetProperty("IMPORTED_LOCATION")) { - result = location; + result = *location; } } break; case cmStateEnums::ImportLibraryArtifact: if (imp) { - result = imp; + result = *imp; } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->IsExecutableWithExports()) { std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix); - if (const char* config_implib = this->GetProperty(impProp)) { - result = config_implib; - } else if (const char* implib = - this->GetProperty("IMPORTED_IMPLIB")) { - result = implib; + if (cmProp config_implib = this->GetProperty(impProp)) { + result = *config_implib; + } else if (cmProp implib = this->GetProperty("IMPORTED_IMPLIB")) { + result = *implib; } } break; @@ -1992,9 +2007,8 @@ bool cmTargetInternals::CheckImportedLibName(std::string const& prop, return true; } -bool cmTarget::GetMappedConfig(std::string const& desired_config, - const char** loc, const char** imp, - std::string& suffix) const +bool cmTarget::GetMappedConfig(std::string const& desired_config, cmProp& loc, + cmProp& imp, std::string& suffix) const { std::string config_upper; if (!desired_config.empty()) { @@ -2016,8 +2030,8 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config, std::vector<std::string> mappedConfigs; { std::string mapProp = cmStrCat("MAP_IMPORTED_CONFIG_", config_upper); - if (const char* mapValue = this->GetProperty(mapProp)) { - cmExpandList(mapValue, mappedConfigs, true); + if (cmProp mapValue = this->GetProperty(mapProp)) { + cmExpandList(*mapValue, mappedConfigs, true); } } @@ -2031,30 +2045,30 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config, // If a mapping was found, check its configurations. for (auto mci = mappedConfigs.begin(); - !*loc && !*imp && mci != mappedConfigs.end(); ++mci) { + !loc && !imp && mci != mappedConfigs.end(); ++mci) { // Look for this configuration. if (mci->empty()) { // An empty string in the mapping has a special meaning: // look up the config-less properties. - *loc = this->GetProperty(locPropBase); + loc = this->GetProperty(locPropBase); if (allowImp) { - *imp = this->GetProperty("IMPORTED_IMPLIB"); + imp = this->GetProperty("IMPORTED_IMPLIB"); } // If it was found, set the suffix. - if (*loc || *imp) { + if (loc || imp) { suffix.clear(); } } else { std::string mcUpper = cmSystemTools::UpperCase(*mci); std::string locProp = cmStrCat(locPropBase, '_', mcUpper); - *loc = this->GetProperty(locProp); + loc = this->GetProperty(locProp); if (allowImp) { std::string impProp = cmStrCat("IMPORTED_IMPLIB_", mcUpper); - *imp = this->GetProperty(impProp); + imp = this->GetProperty(impProp); } // If it was found, use it for all properties below. - if (*loc || *imp) { + if (loc || imp) { suffix = cmStrCat('_', mcUpper); } } @@ -2063,59 +2077,59 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config, // If we needed to find one of the mapped configurations but did not // then the target location is not found. The project does not want // any other configuration. - if (!mappedConfigs.empty() && !*loc && !*imp) { + if (!mappedConfigs.empty() && !loc && !imp) { // Interface libraries are always available because their - // library name is optional so it is okay to leave *loc empty. + // library name is optional so it is okay to leave loc empty. return this->GetType() == cmStateEnums::INTERFACE_LIBRARY; } // If we have not yet found it then there are no mapped // configurations. Look for an exact-match. - if (!*loc && !*imp) { + if (!loc && !imp) { std::string locProp = cmStrCat(locPropBase, suffix); - *loc = this->GetProperty(locProp); + loc = this->GetProperty(locProp); if (allowImp) { std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix); - *imp = this->GetProperty(impProp); + imp = this->GetProperty(impProp); } } // If we have not yet found it then there are no mapped // configurations and no exact match. - if (!*loc && !*imp) { + if (!loc && !imp) { // The suffix computed above is not useful. suffix.clear(); // Look for a configuration-less location. This may be set by // manually-written code. - *loc = this->GetProperty(locPropBase); + loc = this->GetProperty(locPropBase); if (allowImp) { - *imp = this->GetProperty("IMPORTED_IMPLIB"); + imp = this->GetProperty("IMPORTED_IMPLIB"); } } // If we have not yet found it then the project is willing to try // any available configuration. - if (!*loc && !*imp) { + if (!loc && !imp) { std::vector<std::string> availableConfigs; - if (const char* iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) { - cmExpandList(iconfigs, availableConfigs); + if (cmProp iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) { + cmExpandList(*iconfigs, availableConfigs); } for (auto aci = availableConfigs.begin(); - !*loc && !*imp && aci != availableConfigs.end(); ++aci) { + !loc && !imp && aci != availableConfigs.end(); ++aci) { suffix = cmStrCat('_', cmSystemTools::UpperCase(*aci)); std::string locProp = cmStrCat(locPropBase, suffix); - *loc = this->GetProperty(locProp); + loc = this->GetProperty(locProp); if (allowImp) { std::string impProp = cmStrCat("IMPORTED_IMPLIB", suffix); - *imp = this->GetProperty(impProp); + imp = this->GetProperty(impProp); } } } // If we have not yet found it then the target location is not available. - if (!*loc && !*imp) { + if (!loc && !imp) { // Interface libraries are always available because their - // library name is optional so it is okay to leave *loc empty. + // library name is optional so it is okay to leave loc empty. return this->GetType() == cmStateEnums::INTERFACE_LIBRARY; } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 286933b51..f0ddb686a 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -15,6 +15,7 @@ #include "cmAlgorithms.h" #include "cmListFileCache.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmTargetLinkLibraryType.h" @@ -43,8 +44,14 @@ public: VisibilityImportedGlobally }; + enum class PerConfig + { + Yes, + No + }; + cmTarget(std::string const& name, cmStateEnums::TargetType type, - Visibility vis, cmMakefile* mf, bool perConfig); + Visibility vis, cmMakefile* mf, PerConfig perConfig); cmTarget(cmTarget const&) = delete; cmTarget(cmTarget&&) noexcept; @@ -170,14 +177,13 @@ public: 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; + cmProp GetProperty(const std::string& prop) const; //! Always returns a valid pointer - const char* GetSafeProperty(const std::string& prop) const; + std::string const& GetSafeProperty(std::string const& prop) const; bool GetPropertyAsBool(const std::string& prop) const; void CheckProperty(const std::string& prop, cmMakefile* context) const; - const char* GetComputedProperty(const std::string& prop, - cmMessenger* messenger, - cmListFileBacktrace const& context) const; + cmProp GetComputedProperty(const std::string& prop, cmMessenger* messenger, + cmListFileBacktrace const& context) const; //! Get all properties cmPropertyMap const& GetProperties() const; @@ -191,8 +197,8 @@ public: bool IsImportedGloballyVisible() const; bool IsPerConfig() const; - bool GetMappedConfig(std::string const& desired_config, const char** loc, - const char** imp, std::string& suffix) const; + bool GetMappedConfig(std::string const& desired_config, cmProp& loc, + cmProp& imp, std::string& suffix) const; //! Return whether this target is an executable with symbol exports enabled. bool IsExecutableWithExports() const; diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index 0de8d6d05..e7147209b 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -5,6 +5,7 @@ #include "cmExecutionStatus.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmStateTypes.h" #include "cmTarget.h" #include "cmake.h" @@ -157,9 +158,9 @@ void cmTargetPropCommandBase::HandleInterfaceContent( { if (prepend) { const std::string propName = std::string("INTERFACE_") + this->Property; - const char* propValue = tgt->GetProperty(propName); - const std::string totalContent = this->Join(content) + - (propValue ? std::string(";") + propValue : std::string()); + cmProp propValue = tgt->GetProperty(propName); + const std::string totalContent = + this->Join(content) + (propValue ? (";" + *propValue) : std::string()); tgt->SetProperty(propName, totalContent); } else { tgt->AppendProperty("INTERFACE_" + this->Property, this->Join(content)); diff --git a/Source/cmTargetPropertyComputer.h b/Source/cmTargetPropertyComputer.h index df34f188d..f87b7c2d2 100644 --- a/Source/cmTargetPropertyComputer.h +++ b/Source/cmTargetPropertyComputer.h @@ -8,6 +8,7 @@ #include <string> #include "cmListFileCache.h" +#include "cmProperty.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -18,11 +19,11 @@ class cmTargetPropertyComputer { public: template <typename Target> - static const char* GetProperty(Target const* tgt, const std::string& prop, - cmMessenger* messenger, - cmListFileBacktrace const& context) + static cmProp GetProperty(Target const* tgt, const std::string& prop, + cmMessenger* messenger, + cmListFileBacktrace const& context) { - if (const char* loc = GetLocation(tgt, prop, messenger, context)) { + if (cmProp loc = GetLocation(tgt, prop, messenger, context)) { return loc; } if (cmSystemTools::GetFatalErrorOccured()) { @@ -52,9 +53,9 @@ private: std::string const& config); template <typename Target> - static const char* GetLocation(Target const* tgt, std::string const& prop, - cmMessenger* messenger, - cmListFileBacktrace const& context) + static cmProp GetLocation(Target const* tgt, std::string const& prop, + cmMessenger* messenger, + cmListFileBacktrace const& context) { // Watch for special "computed" properties that are dependent on @@ -71,7 +72,7 @@ private: context)) { return nullptr; } - return ComputeLocationForBuild(tgt).c_str(); + return &ComputeLocationForBuild(tgt); } // Support "LOCATION_<CONFIG>". @@ -82,7 +83,7 @@ private: return nullptr; } std::string configName = prop.substr(9); - return ComputeLocation(tgt, configName).c_str(); + return &ComputeLocation(tgt, configName); } // Support "<CONFIG>_LOCATION". @@ -95,7 +96,7 @@ private: context)) { return nullptr; } - return ComputeLocation(tgt, configName).c_str(); + return &ComputeLocation(tgt, configName); } } } @@ -103,8 +104,8 @@ private: } template <typename Target> - static const char* GetSources(Target const* tgt, cmMessenger* messenger, - cmListFileBacktrace const& context); + static cmProp GetSources(Target const* tgt, cmMessenger* messenger, + cmListFileBacktrace const& context); }; #endif diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx index 3b731cc5b..a26bef3db 100644 --- a/Source/cmTest.cxx +++ b/Source/cmTest.cxx @@ -34,15 +34,18 @@ void cmTest::SetCommand(std::vector<std::string> const& command) const char* cmTest::GetProperty(const std::string& prop) const { - const char* retVal = this->Properties.GetPropertyValue(prop); + cmProp retVal = this->Properties.GetPropertyValue(prop); if (!retVal) { const bool chain = this->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TEST); if (chain) { - return this->Makefile->GetProperty(prop, chain); + if (cmProp p = this->Makefile->GetProperty(prop, chain)) { + return p->c_str(); + } } + return nullptr; } - return retVal; + return retVal->c_str(); } bool cmTest::GetPropertyAsBool(const std::string& prop) const diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index 333d4d5ee..e10a8e207 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -12,6 +12,7 @@ #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmPropertyMap.h" #include "cmRange.h" #include "cmStateTypes.h" @@ -76,7 +77,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, cmGeneratorExpression ge(this->Test->GetBacktrace()); // Start the test command. - os << indent << "add_test(" << this->Test->GetName() << " "; + os << indent << "add_test(\"" << this->Test->GetName() << "\" "; // Evaluate command line arguments std::vector<std::string> argv = @@ -100,9 +101,9 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, exe = target->GetFullPath(config); // Prepend with the emulator when cross compiling if required. - const char* emulator = target->GetProperty("CROSSCOMPILING_EMULATOR"); - if (emulator != nullptr && *emulator) { - std::vector<std::string> emulatorWithArgs = cmExpandedList(emulator); + cmProp emulator = target->GetProperty("CROSSCOMPILING_EMULATOR"); + if (emulator != nullptr && !emulator->empty()) { + std::vector<std::string> emulatorWithArgs = cmExpandedList(*emulator); std::string emulatorExe(emulatorWithArgs[0]); cmSystemTools::ConvertToUnixSlashes(emulatorExe); os << cmOutputConverter::EscapeForCMake(emulatorExe) << " "; @@ -126,20 +127,21 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, os << ")\n"; // Output properties for the test. - os << indent << "set_tests_properties(" << this->Test->GetName() - << " PROPERTIES "; + os << indent << "set_tests_properties(\"" << this->Test->GetName() + << "\" PROPERTIES "; for (auto const& i : this->Test->GetProperties().GetList()) { os << " " << i.first << " " << cmOutputConverter::EscapeForCMake( ge.Parse(i.second)->Evaluate(this->LG, config)); } this->GenerateInternalProperties(os); - os << ")" << std::endl; + os << ")\n"; } void cmTestGenerator::GenerateScriptNoConfig(std::ostream& os, Indent indent) { - os << indent << "add_test(" << this->Test->GetName() << " NOT_AVAILABLE)\n"; + os << indent << "add_test(\"" << this->Test->GetName() + << "\" NOT_AVAILABLE)\n"; } bool cmTestGenerator::NeedsScriptNoConfig() const @@ -159,9 +161,8 @@ void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent) std::string exe = command[0]; cmSystemTools::ConvertToUnixSlashes(exe); - fout << indent; - fout << "add_test("; - fout << this->Test->GetName() << " \"" << exe << "\""; + fout << indent << "add_test(\"" << this->Test->GetName() << "\" \"" << exe + << "\""; for (std::string const& arg : cmMakeRange(command).advance(1)) { // Just double-quote all arguments so they are re-parsed @@ -176,9 +177,9 @@ void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent) } fout << c; } - fout << "\""; + fout << '"'; } - fout << ")" << std::endl; + fout << ")\n"; // Output properties for the test. fout << indent << "set_tests_properties(" << this->Test->GetName() @@ -188,7 +189,7 @@ void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent) << cmOutputConverter::EscapeForCMake(i.second); } this->GenerateInternalProperties(fout); - fout << ")" << std::endl; + fout << ")\n"; } void cmTestGenerator::GenerateInternalProperties(std::ostream& os) @@ -213,7 +214,7 @@ void cmTestGenerator::GenerateInternalProperties(std::ostream& os) prependTripleSeparator = true; } - os << "\""; + os << '"'; } std::vector<std::string> cmTestGenerator::EvaluateCommandLineArguments( diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index 390fd16b0..13f73dc48 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -1,5 +1,15 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ + +#if !defined(_WIN32) && !defined(__sun) +// POSIX APIs are needed +# define _POSIX_C_SOURCE 200809L +#endif +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) +// For isascii +# define _XOPEN_SOURCE 700 +#endif + #include "cmTimestamp.h" #include <cstdlib> diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx index 0e8e986ab..64d71bcda 100644 --- a/Source/cmTryRunCommand.cxx +++ b/Source/cmTryRunCommand.cxx @@ -9,6 +9,7 @@ #include "cmDuration.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmState.h" #include "cmStateTypes.h" @@ -242,8 +243,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs, comment.c_str(), cmStateEnums::STRING); cmState* state = this->Makefile->GetState(); - const char* existingValue = - state->GetCacheEntryValue(this->RunResultVariable); + cmProp existingValue = state->GetCacheEntryValue(this->RunResultVariable); if (existingValue) { state->SetCacheEntryProperty(this->RunResultVariable, "ADVANCED", "1"); } @@ -265,7 +265,7 @@ void cmTryRunCommand::DoNotRunExecutable(const std::string& runArgs, internalRunOutputName, "PLEASE_FILL_OUT-NOTFOUND", comment.c_str(), cmStateEnums::STRING); cmState* state = this->Makefile->GetState(); - const char* existing = state->GetCacheEntryValue(internalRunOutputName); + cmProp existing = state->GetCacheEntryValue(internalRunOutputName); if (existing) { state->SetCacheEntryProperty(internalRunOutputName, "ADVANCED", "1"); } diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx index 23dabb770..df2f64ec5 100644 --- a/Source/cmUVHandlePtr.cxx +++ b/Source/cmUVHandlePtr.cxx @@ -7,7 +7,7 @@ #include <cstdlib> #include <mutex> -#include "cm_uv.h" +#include <cm3p/uv.h> namespace cm { diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h index 3083b60c8..d9de7f3da 100644 --- a/Source/cmUVHandlePtr.h +++ b/Source/cmUVHandlePtr.h @@ -8,7 +8,7 @@ #include <memory> #include <type_traits> -#include "cm_uv.h" +#include <cm3p/uv.h> #if defined(__SUNPRO_CC) diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx index 543c3308a..6040fd816 100644 --- a/Source/cmUVProcessChain.cxx +++ b/Source/cmUVProcessChain.cxx @@ -9,7 +9,7 @@ #include <cm/memory> -#include "cm_uv.h" +#include <cm3p/uv.h> #include "cmGetPipes.h" #include "cmUVHandlePtr.h" diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h index 05a7cc82c..b5ccb19f1 100644 --- a/Source/cmUVProcessChain.h +++ b/Source/cmUVProcessChain.h @@ -4,14 +4,14 @@ #define cmUVProcessChain_h #include <array> -#include <cstddef> +#include <cstddef> // IWYU pragma: keep #include <cstdint> #include <iosfwd> #include <memory> #include <string> #include <vector> -#include "cm_uv.h" +#include <cm3p/uv.h> class cmUVProcessChain; diff --git a/Source/cmUVSignalHackRAII.h b/Source/cmUVSignalHackRAII.h index 63599db82..60e4ca84e 100644 --- a/Source/cmUVSignalHackRAII.h +++ b/Source/cmUVSignalHackRAII.h @@ -3,7 +3,7 @@ #pragma once #include "cmConfigure.h" // IWYU pragma: keep -#include "cm_uv.h" +#include <cm3p/uv.h> #if defined(CMAKE_USE_SYSTEM_LIBUV) && !defined(_WIN32) && \ UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR < 19 diff --git a/Source/cmUVStreambuf.h b/Source/cmUVStreambuf.h index 1c8a7717c..50faede83 100644 --- a/Source/cmUVStreambuf.h +++ b/Source/cmUVStreambuf.h @@ -8,7 +8,7 @@ #include <streambuf> #include <vector> -#include "cm_uv.h" +#include <cm3p/uv.h> #include "cmUVHandlePtr.h" diff --git a/Source/cmUtilitySourceCommand.cxx b/Source/cmUtilitySourceCommand.cxx index a43165cce..6de78ff67 100644 --- a/Source/cmUtilitySourceCommand.cxx +++ b/Source/cmUtilitySourceCommand.cxx @@ -84,8 +84,8 @@ bool cmUtilitySourceCommand(std::vector<std::string> const& args, std::string utilityDirectory = status.GetMakefile().GetCurrentBinaryDirectory(); std::string exePath; - if (status.GetMakefile().GetDefinition("EXECUTABLE_OUTPUT_PATH")) { - exePath = status.GetMakefile().GetDefinition("EXECUTABLE_OUTPUT_PATH"); + if (auto d = status.GetMakefile().GetDefinition("EXECUTABLE_OUTPUT_PATH")) { + exePath = d; } if (!exePath.empty()) { utilityDirectory = exePath; @@ -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/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index dd9f058b8..9626599a3 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -258,6 +258,20 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo(std::string& vsInstallLocation) return isInstalled; } +bool cmVSSetupAPIHelper::GetVSInstanceVersion( + unsigned long long& vsInstanceVersion) +{ + vsInstanceVersion = 0; + bool isInstalled = this->EnumerateAndChooseVSInstance(); + + if (isInstalled) { + vsInstanceVersion = + static_cast<unsigned long long>(chosenInstanceInfo.ullVersion); + } + + return isInstalled; +} + bool cmVSSetupAPIHelper::GetVCToolsetVersion(std::string& vsToolsetVersion) { vsToolsetVersion.clear(); diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index 0980cef53..a926eee92 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -8,13 +8,12 @@ #endif // Published by Visual Studio Setup team +#include <cm3p/Setup.Configuration.h> #include <string> #include <vector> #include <windows.h> -#include "cmvssetup/Setup.Configuration.h" - template <class T> class SmartCOMPtr { @@ -107,6 +106,7 @@ public: bool IsVSInstalled(); bool GetVSInstanceInfo(std::string& vsInstallLocation); + bool GetVSInstanceVersion(unsigned long long& vsInstanceVersion); bool GetVCToolsetVersion(std::string& vsToolsetVersion); bool IsWin10SDKInstalled(); bool IsWin81SDKInstalled(); diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx index 35b9a1d5b..ecae16dae 100644 --- a/Source/cmVariableWatchCommand.cxx +++ b/Source/cmVariableWatchCommand.cxx @@ -42,7 +42,7 @@ void cmVariableWatchCommandVariableAccessed(const std::string& variable, /// Ultra bad!! cmMakefile* makefile = const_cast<cmMakefile*>(mf); - std::string stack = makefile->GetProperty("LISTFILE_STACK"); + std::string stack = *mf->GetProperty("LISTFILE_STACK"); if (!data->Command.empty()) { cmListFileFunction newLFF; const char* const currentListFile = diff --git a/Source/cmVersion.h b/Source/cmVersion.h index bfd994d09..932ef0467 100644 --- a/Source/cmVersion.h +++ b/Source/cmVersion.h @@ -3,7 +3,7 @@ #ifndef cmVersion_h #define cmVersion_h -#include "cm_kwiml.h" +#include <cm3p/kwiml/int.h> /** \class cmVersion * \brief Helper class for providing CMake and CTest version information. diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 163ff19d8..a3ccd2bae 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -6,11 +6,12 @@ #include <set> #include <cm/memory> +#include <cm/string_view> #include <cm/vector> +#include <cmext/algorithm> #include "windows.h" -#include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" @@ -18,10 +19,12 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalVisualStudio10Generator.h" +#include "cmGlobalVisualStudioVersionedGenerator.h" #include "cmLinkLineDeviceComputer.h" #include "cmLocalVisualStudio10Generator.h" #include "cmMakefile.h" #include "cmSourceFile.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmVisualStudioGeneratorOptions.h" @@ -61,10 +64,10 @@ struct cmVisualStudio10TargetGenerator::Elem this->StartElement(); } Elem(const Elem&) = delete; - Elem(Elem& par, const std::string& tag) + Elem(Elem& par, cm::string_view tag) : S(par.S) , Indent(par.Indent + 1) - , Tag(tag) + , Tag(std::string(tag)) { par.SetHasElements(); this->StartElement(); @@ -78,22 +81,22 @@ struct cmVisualStudio10TargetGenerator::Elem } std::ostream& WriteString(const char* line); void StartElement() { this->WriteString("<") << this->Tag; } - void Element(const std::string& tag, const std::string& val) + void Element(cm::string_view tag, std::string val) { - Elem(*this, tag).Content(val); + Elem(*this, tag).Content(std::move(val)); } - Elem& Attribute(const char* an, const std::string& av) + Elem& Attribute(const char* an, std::string av) { - this->S << " " << an << "=\"" << cmVS10EscapeAttr(av) << "\""; + this->S << " " << an << "=\"" << cmVS10EscapeAttr(std::move(av)) << "\""; return *this; } - void Content(const std::string& val) + void Content(std::string val) { if (!this->HasContent) { this->S << ">"; this->HasContent = true; } - this->S << cmVS10EscapeXML(val); + this->S << cmVS10EscapeXML(std::move(val)); } ~Elem() { @@ -246,6 +249,7 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); this->InSourceBuild = (this->Makefile->GetCurrentSourceDirectory() == this->Makefile->GetCurrentBinaryDirectory()); + this->ClassifyAllConfigSources(); } cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator() @@ -429,32 +433,32 @@ void cmVisualStudio10TargetGenerator::Generate() this->VerifyNecessaryFiles(); } - const char* vsProjectTypes = + cmProp vsProjectTypes = this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES"); if (vsProjectTypes) { const char* tagName = "ProjectTypes"; if (this->ProjectType == csproj) { tagName = "ProjectTypeGuids"; } - e1.Element(tagName, vsProjectTypes); + e1.Element(tagName, *vsProjectTypes); } - const char* vsProjectName = + cmProp vsProjectName = this->GeneratorTarget->GetProperty("VS_SCC_PROJECTNAME"); - const char* vsLocalPath = + cmProp vsLocalPath = this->GeneratorTarget->GetProperty("VS_SCC_LOCALPATH"); - const char* vsProvider = + cmProp vsProvider = this->GeneratorTarget->GetProperty("VS_SCC_PROVIDER"); if (vsProjectName && vsLocalPath && vsProvider) { - e1.Element("SccProjectName", vsProjectName); - e1.Element("SccLocalPath", vsLocalPath); - e1.Element("SccProvider", vsProvider); + e1.Element("SccProjectName", *vsProjectName); + e1.Element("SccLocalPath", *vsLocalPath); + e1.Element("SccProvider", *vsProvider); - const char* vsAuxPath = + cmProp vsAuxPath = this->GeneratorTarget->GetProperty("VS_SCC_AUXPATH"); if (vsAuxPath) { - e1.Element("SccAuxPath", vsAuxPath); + e1.Element("SccAuxPath", *vsAuxPath); } } @@ -462,45 +466,44 @@ void cmVisualStudio10TargetGenerator::Generate() e1.Element("WinMDAssembly", "true"); } - const char* vsGlobalKeyword = + cmProp vsGlobalKeyword = this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD"); if (!vsGlobalKeyword) { e1.Element("Keyword", "Win32Proj"); } else { - e1.Element("Keyword", vsGlobalKeyword); + e1.Element("Keyword", *vsGlobalKeyword); } - const char* vsGlobalRootNamespace = + cmProp vsGlobalRootNamespace = this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE"); if (vsGlobalRootNamespace) { - e1.Element("RootNamespace", vsGlobalRootNamespace); + e1.Element("RootNamespace", *vsGlobalRootNamespace); } e1.Element("Platform", this->Platform); - const char* projLabel = - this->GeneratorTarget->GetProperty("PROJECT_LABEL"); + cmProp projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL"); if (!projLabel) { - projLabel = this->Name.c_str(); + projLabel = &this->Name; } - e1.Element("ProjectName", projLabel); + e1.Element("ProjectName", *projLabel); { - const char* targetFramework = + cmProp targetFramework = this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK"); if (targetFramework) { - if (std::strchr(targetFramework, ';') != nullptr) { - e1.Element("TargetFrameworks", targetFramework); + if (std::strchr(targetFramework->c_str(), ';') != nullptr) { + e1.Element("TargetFrameworks", *targetFramework); } else { - e1.Element("TargetFramework", targetFramework); + 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( + cmProp p = this->GeneratorTarget->GetProperty( + "VS_DOTNET_TARGET_FRAMEWORK_VERSION"); + if (!p) { + p = this->GeneratorTarget->GetProperty( "DOTNET_TARGET_FRAMEWORK_VERSION"); } + const char* targetFrameworkVersion = p ? p->c_str() : nullptr; if (!targetFrameworkVersion && this->ProjectType == csproj && this->GlobalGenerator->TargetsWindowsCE() && this->GlobalGenerator->GetVersion() == @@ -519,18 +522,15 @@ void cmVisualStudio10TargetGenerator::Generate() } if (this->ProjectType == csproj && this->GlobalGenerator->TargetsWindowsCE()) { - const char* targetFrameworkId = this->GeneratorTarget->GetProperty( + cmProp targetFrameworkId = this->GeneratorTarget->GetProperty( "VS_TARGET_FRAMEWORK_IDENTIFIER"); - if (!targetFrameworkId) { - targetFrameworkId = "WindowsEmbeddedCompact"; - } - e1.Element("TargetFrameworkIdentifier", targetFrameworkId); - const char* targetFrameworkVer = this->GeneratorTarget->GetProperty( + e1.Element("TargetFrameworkIdentifier", + targetFrameworkId ? *targetFrameworkId + : "WindowsEmbeddedCompact"); + cmProp targetFrameworkVer = this->GeneratorTarget->GetProperty( "VS_TARGET_FRAMEWORKS_TARGET_VERSION"); - if (!targetFrameworkVer) { - targetFrameworkVer = "v8.0"; - } - e1.Element("TargetFrameworkTargetsVersion", targetFrameworkVer); + e1.Element("TargetFrameworkTargetsVersion", + targetFrameworkVer ? *targetFrameworkVer : "v8.0"); } if (!this->GlobalGenerator->GetPlatformToolsetCudaCustomDirString() .empty()) { @@ -556,19 +556,20 @@ void cmVisualStudio10TargetGenerator::Generate() std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys(); for (std::string const& keyIt : keys) { - static const char* prefix = "VS_GLOBAL_"; - if (keyIt.find(prefix) != 0) + static const cm::string_view prefix = "VS_GLOBAL_"; + if (!cmHasPrefix(keyIt, prefix)) continue; - std::string globalKey = keyIt.substr(strlen(prefix)); + cm::string_view globalKey = + cm::string_view(keyIt).substr(prefix.length()); // Skip invalid or separately-handled properties. if (globalKey.empty() || globalKey == "PROJECT_TYPES" || globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") { continue; } - const char* value = this->GeneratorTarget->GetProperty(keyIt); + cmProp value = this->GeneratorTarget->GetProperty(keyIt); if (!value) continue; - e1.Element(globalKey, value); + e1.Element(globalKey, *value); } if (this->Managed) { @@ -673,9 +674,8 @@ void cmVisualStudio10TargetGenerator::Generate() props = VS10_CSharp_USER_PROPS; break; } - if (const char* p = - this->GeneratorTarget->GetProperty("VS_USER_PROPS")) { - props = p; + if (cmProp p = this->GeneratorTarget->GetProperty("VS_USER_PROPS")) { + props = *p; } if (!props.empty()) { ConvertToWindowsSlash(props); @@ -781,50 +781,41 @@ void cmVisualStudio10TargetGenerator::Generate() void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0) { std::vector<std::string> packageReferences; - if (const char* vsPackageReferences = + if (cmProp vsPackageReferences = this->GeneratorTarget->GetProperty("VS_PACKAGE_REFERENCES")) { - cmExpandList(vsPackageReferences, packageReferences); + cmExpandList(*vsPackageReferences, packageReferences); } if (!packageReferences.empty()) { Elem e1(e0, "ItemGroup"); for (std::string const& ri : packageReferences) { size_t versionIndex = ri.find_last_of('_'); if (versionIndex != std::string::npos) { - WritePackageReference(e1, ri.substr(0, versionIndex), - ri.substr(versionIndex + 1)); + Elem e2(e1, "PackageReference"); + e2.Attribute("Include", ri.substr(0, versionIndex)); + e2.Attribute("Version", ri.substr(versionIndex + 1)); } } } } -void cmVisualStudio10TargetGenerator::WritePackageReference( - Elem& e1, std::string const& ref, std::string const& version) -{ - Elem e2(e1, "PackageReference"); - e2.Attribute("Include", ref); - e2.Attribute("Version", version); -} - void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0) { std::vector<std::string> references; - if (const char* vsDotNetReferences = + if (cmProp vsDotNetReferences = this->GeneratorTarget->GetProperty("VS_DOTNET_REFERENCES")) { - cmExpandList(vsDotNetReferences, references); + cmExpandList(*vsDotNetReferences, references); } cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties(); for (auto const& i : props.GetList()) { - if (i.first.find("VS_DOTNET_REFERENCE_") == 0) { - std::string name = i.first.substr(20); - if (!name.empty()) { - std::string path = i.second; - if (!cmsys::SystemTools::FileIsFullPath(path)) { - path = this->Makefile->GetCurrentSourceDirectory() + "/" + path; - } - ConvertToWindowsSlash(path); - this->DotNetHintReferences[""].push_back( - DotNetHintReference(name, path)); + static const cm::string_view vsDnRef = "VS_DOTNET_REFERENCE_"; + if (cmHasPrefix(i.first, vsDnRef)) { + std::string path = i.second; + if (!cmsys::SystemTools::FileIsFullPath(path)) { + path = this->Makefile->GetCurrentSourceDirectory() + "/" + path; } + ConvertToWindowsSlash(path); + this->DotNetHintReferences[""].emplace_back( + DotNetHintReference(i.first.substr(vsDnRef.length()), path)); } } if (!references.empty() || !this->DotNetHintReferences.empty()) { @@ -837,7 +828,7 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0) cmsys::SystemTools::GetFilenameWithoutLastExtension(ri); std::string path = ri; ConvertToWindowsSlash(path); - this->DotNetHintReferences[""].push_back( + this->DotNetHintReferences[""].emplace_back( DotNetHintReference(name, path)); } else { this->WriteDotNetReference(e1, ri, "", ""); @@ -869,9 +860,9 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReference( e2.Element("ReferenceOutputAssembly", "true"); if (!hint.empty()) { const char* privateReference = "True"; - if (const char* value = this->GeneratorTarget->GetProperty( + if (cmProp value = this->GeneratorTarget->GetProperty( "VS_DOTNET_REFERENCES_COPY_LOCAL")) { - if (cmIsOff(value)) { + if (cmIsOff(*value)) { privateReference = "False"; } } @@ -883,11 +874,10 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReference( void cmVisualStudio10TargetGenerator::WriteImports(Elem& e0) { - const char* imports = + cmProp imports = this->GeneratorTarget->Target->GetProperty("VS_PROJECT_IMPORT"); if (imports) { - std::vector<std::string> argsSplit = - cmExpandedList(std::string(imports), false); + std::vector<std::string> argsSplit = cmExpandedList(*imports, false); for (auto& path : argsSplit) { if (!cmsys::SystemTools::FileIsFullPath(path)) { path = this->Makefile->GetCurrentSourceDirectory() + "/" + path; @@ -910,12 +900,8 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferenceCustomTags( CustomTags tags; cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties(); for (const auto& i : props.GetList()) { - if (i.first.find(refPropFullPrefix) == 0) { - std::string refTag = i.first.substr(refPropFullPrefix.length()); - std::string refVal = i.second; - if (!refTag.empty() && !refVal.empty()) { - tags[refTag] = refVal; - } + if (cmHasPrefix(i.first, refPropFullPrefix) && !i.second.empty()) { + tags[i.first.substr(refPropFullPrefix.length())] = i.second; } } for (auto const& tag : tags) { @@ -925,7 +911,7 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferenceCustomTags( void cmVisualStudio10TargetGenerator::WriteDotNetDocumentationFile(Elem& e0) { - std::string const documentationFile = + std::string const& documentationFile = this->GeneratorTarget->GetSafeProperty("VS_DOTNET_DOCUMENTATION_FILE"); if (this->ProjectType == csproj && !documentationFile.empty()) { @@ -937,13 +923,11 @@ void cmVisualStudio10TargetGenerator::WriteDotNetDocumentationFile(Elem& e0) void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) { - std::vector<cmSourceFile const*> resxObjs; - this->GeneratorTarget->GetResxSources(resxObjs, ""); - if (!resxObjs.empty()) { + if (!this->ResxObjs.empty()) { Elem e1(e0, "ItemGroup"); std::string srcDir = this->Makefile->GetCurrentSourceDirectory(); ConvertToWindowsSlash(srcDir); - for (cmSourceFile const* oi : resxObjs) { + for (cmSourceFile const* oi : this->ResxObjs) { std::string obj = oi->GetFullPath(); ConvertToWindowsSlash(obj); bool useRelativePath = false; @@ -952,7 +936,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) // subdirectory // of the .csproj file, we have to use relative pathnames, otherwise // visual studio does not show the file in the IDE. Sorry. - if (obj.find(srcDir) == 0) { + if (cmHasPrefix(obj, srcDir)) { obj = this->ConvertPath(obj, true); ConvertToWindowsSlash(obj); useRelativePath = true; @@ -981,17 +965,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,15 +978,15 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) ".Designer.cs"; if (cmsys::SystemTools::FileExists(designerResource)) { std::string generator = "PublicResXFileCodeGenerator"; - if (const char* g = oi->GetProperty("VS_RESOURCE_GENERATOR")) { - generator = g; + if (cmProp g = oi->GetProperty("VS_RESOURCE_GENERATOR")) { + generator = *g; } if (!generator.empty()) { e2.Element("Generator", generator); - if (designerResource.find(srcDir) == 0) { - designerResource = designerResource.substr(srcDir.length() + 1); - } else if (designerResource.find(binDir) == 0) { - designerResource = designerResource.substr(binDir.length() + 1); + if (cmHasPrefix(designerResource, srcDir)) { + designerResource.erase(0, srcDir.length()); + } else if (cmHasPrefix(designerResource, binDir)) { + designerResource.erase(0, binDir.length()); } else { designerResource = cmsys::SystemTools::GetFilenameName(designerResource); @@ -1019,11 +997,12 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) } const cmPropertyMap& props = oi->GetProperties(); for (const std::string& p : props.GetKeys()) { - static const std::string propNamePrefix = "VS_CSHARP_"; - if (p.find(propNamePrefix) == 0) { - std::string tagName = p.substr(propNamePrefix.length()); + static const cm::string_view propNamePrefix = "VS_CSHARP_"; + if (cmHasPrefix(p, propNamePrefix)) { + cm::string_view tagName = + cm::string_view(p).substr(propNamePrefix.length()); if (!tagName.empty()) { - std::string value = props.GetPropertyValue(p); + const std::string& value = *props.GetPropertyValue(p); if (!value.empty()) { e2.Element(tagName, value); } @@ -1037,16 +1016,14 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup(Elem& e0) { - std::vector<cmSourceFile const*> xamlObjs; - this->GeneratorTarget->GetXamlSources(xamlObjs, ""); - if (!xamlObjs.empty()) { + if (!this->XamlObjs.empty()) { Elem e1(e0, "ItemGroup"); - for (cmSourceFile const* oi : xamlObjs) { + for (cmSourceFile const* oi : this->XamlObjs) { std::string obj = oi->GetFullPath(); - const char* xamlType; - const char* xamlTypeProperty = oi->GetProperty("VS_XAML_TYPE"); + std::string xamlType; + cmProp xamlTypeProperty = oi->GetProperty("VS_XAML_TYPE"); if (xamlTypeProperty) { - xamlType = xamlTypeProperty; + xamlType = *xamlTypeProperty; } else { xamlType = "Page"; } @@ -1054,25 +1031,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"); } } @@ -1117,9 +1075,9 @@ void cmVisualStudio10TargetGenerator::WriteTargetsFileReferences(Elem& e1) void cmVisualStudio10TargetGenerator::WriteWinRTReferences(Elem& e0) { std::vector<std::string> references; - if (const char* vsWinRTReferences = + if (cmProp vsWinRTReferences = this->GeneratorTarget->GetProperty("VS_WINRT_REFERENCES")) { - cmExpandList(vsWinRTReferences, references); + cmExpandList(*vsWinRTReferences, references); } if (this->GlobalGenerator->TargetsWindowsPhone() && @@ -1160,9 +1118,9 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues(Elem& e0) if (this->ProjectType != csproj) { std::string configType; - if (const char* vsConfigurationType = + if (cmProp vsConfigurationType = this->GeneratorTarget->GetProperty("VS_CONFIGURATION_TYPE")) { - configType = cmGeneratorExpression::Evaluate(vsConfigurationType, + configType = cmGeneratorExpression::Evaluate(*vsConfigurationType, this->LocalGenerator, c); } else { switch (this->GeneratorTarget->GetType()) { @@ -1218,9 +1176,9 @@ void cmVisualStudio10TargetGenerator::WriteCEDebugProjectConfigurationValues( if (!this->GlobalGenerator->TargetsWindowsCE()) { return; } - const char* additionalFiles = + cmProp additionalFiles = this->GeneratorTarget->GetProperty("DEPLOYMENT_ADDITIONAL_FILES"); - const char* remoteDirectory = + cmProp remoteDirectory = this->GeneratorTarget->GetProperty("DEPLOYMENT_REMOTE_DIRECTORY"); if (!(additionalFiles || remoteDirectory)) { return; @@ -1230,10 +1188,10 @@ void cmVisualStudio10TargetGenerator::WriteCEDebugProjectConfigurationValues( e1.Attribute("Condition", this->CalcCondition(c)); if (remoteDirectory) { - e1.Element("RemoteDirectory", remoteDirectory); + e1.Element("RemoteDirectory", *remoteDirectory); } if (additionalFiles) { - e1.Element("CEAdditionalFiles", additionalFiles); + e1.Element("CEAdditionalFiles", *additionalFiles); } } } @@ -1271,7 +1229,10 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( } else { e1.Element("CharacterSet", "MultiByte"); } - if (const char* toolset = gg->GetPlatformToolset()) { + if (cmProp projectToolsetOverride = + this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) { + e1.Element("PlatformToolset", *projectToolsetOverride); + } else if (const char* toolset = gg->GetPlatformToolset()) { e1.Element("PlatformToolset", toolset); } if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") || @@ -1314,7 +1275,10 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( o.RemoveFlag("Platform"); } - if (const char* toolset = gg->GetPlatformToolset()) { + if (cmProp projectToolsetOverride = + this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) { + e1.Element("PlatformToolset", *projectToolsetOverride); + } else if (const char* toolset = gg->GetPlatformToolset()) { e1.Element("PlatformToolset", toolset); } @@ -1322,8 +1286,8 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX"); std::string assemblyName = this->GeneratorTarget->GetOutputName( config, cmStateEnums::RuntimeBinaryArtifact); - if (const char* postfix = this->GeneratorTarget->GetProperty(postfixName)) { - assemblyName += postfix; + if (cmProp postfix = this->GeneratorTarget->GetProperty(postfixName)) { + assemblyName += *postfix; } e1.Element("AssemblyName", assemblyName); @@ -1343,43 +1307,47 @@ void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues( cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; const char* toolset = gg->GetPlatformToolset(); e1.Element("NdkToolchainVersion", toolset ? toolset : "Default"); - if (const char* minApi = - this->GeneratorTarget->GetProperty("ANDROID_API_MIN")) { - e1.Element("AndroidMinAPI", "android-" + std::string(minApi)); + if (cmProp minApi = this->GeneratorTarget->GetProperty("ANDROID_API_MIN")) { + e1.Element("AndroidMinAPI", "android-" + *minApi); } - if (const char* api = this->GeneratorTarget->GetProperty("ANDROID_API")) { - e1.Element("AndroidTargetAPI", "android-" + std::string(api)); + if (cmProp api = this->GeneratorTarget->GetProperty("ANDROID_API")) { + e1.Element("AndroidTargetAPI", "android-" + *api); } - if (const char* cpuArch = - this->GeneratorTarget->GetProperty("ANDROID_ARCH")) { - e1.Element("AndroidArch", cpuArch); + if (cmProp cpuArch = this->GeneratorTarget->GetProperty("ANDROID_ARCH")) { + e1.Element("AndroidArch", *cpuArch); } - if (const char* stlType = + if (cmProp stlType = this->GeneratorTarget->GetProperty("ANDROID_STL_TYPE")) { - e1.Element("AndroidStlType", stlType); + e1.Element("AndroidStlType", *stlType); } } void cmVisualStudio10TargetGenerator::WriteCustomCommands(Elem& e0) { this->CSharpCustomCommandNames.clear(); - std::vector<cmSourceFile const*> customCommands; - this->GeneratorTarget->GetCustomCommands(customCommands, ""); - for (cmSourceFile const* si : customCommands) { - this->WriteCustomCommand(e0, si); + + cmSourceFile const* srcCMakeLists = + this->LocalGenerator->CreateVCProjBuildRule(); + + for (cmGeneratorTarget::AllConfigSource const& si : + this->GeneratorTarget->GetAllConfigSources()) { + if (si.Source == srcCMakeLists) { + // Skip explicit reference to CMakeLists.txt source. + continue; + } + this->WriteCustomCommand(e0, si.Source); } // Add CMakeLists.txt file with rule to re-run CMake for user convenience. if (this->GeneratorTarget->GetType() != cmStateEnums::GLOBAL_TARGET && this->GeneratorTarget->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { - if (cmSourceFile const* sf = - this->LocalGenerator->CreateVCProjBuildRule()) { + if (srcCMakeLists) { // Write directly rather than through WriteCustomCommand because // we do not want the de-duplication and it has no dependencies. - if (cmCustomCommand const* command = sf->GetCustomCommand()) { - this->WriteCustomRule(e0, sf, *command); + if (cmCustomCommand const* command = srcCMakeLists->GetCustomCommand()) { + this->WriteCustomRule(e0, srcCMakeLists, *command); } } } @@ -1439,16 +1407,14 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( spe2 = cm::make_unique<Elem>(*spe1, "CustomBuild"); this->WriteSource(*spe2, source); spe2->SetHasElements(); + if (command.GetStdPipesUTF8()) { + this->WriteStdOutEncodingUtf8(*spe2); + } } 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); @@ -1662,11 +1628,9 @@ void cmVisualStudio10TargetGenerator::WriteGroups() } } - std::vector<cmSourceFile const*> resxObjs; - this->GeneratorTarget->GetResxSources(resxObjs, ""); - if (!resxObjs.empty()) { + if (!this->ResxObjs.empty()) { Elem e1(e0, "ItemGroup"); - for (cmSourceFile const* oi : resxObjs) { + for (cmSourceFile const* oi : this->ResxObjs) { std::string obj = oi->GetFullPath(); ConvertToWindowsSlash(obj); Elem e2(e1, "EmbeddedResource"); @@ -1694,7 +1658,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups() } } - if (!resxObjs.empty() || !this->AddedFiles.empty()) { + if (!this->ResxObjs.empty() || !this->AddedFiles.empty()) { std::string guidName = "SG_Filter_Resource Files"; std::string guid = this->GlobalGenerator->GetGUID(guidName); Elem e2(e1, "Filter"); @@ -1779,9 +1743,63 @@ void cmVisualStudio10TargetGenerator::WriteHeaderSource(Elem& e1, if (this->IsResxHeader(fileName)) { e2.Element("FileType", "CppForm"); } else if (this->IsXamlHeader(fileName)) { - std::string xamlFileName = fileName.substr(0, fileName.find_last_of(".")); - e2.Element("DependentUpon", xamlFileName); + e2.Element("DependentUpon", + fileName.substr(0, fileName.find_last_of("."))); + } +} + +void cmVisualStudio10TargetGenerator::ParseSettingsProperty( + const std::string& settingsPropertyValue, ConfigToSettings& toolSettings) +{ + if (!settingsPropertyValue.empty()) { + cmGeneratorExpression ge; + + std::unique_ptr<cmCompiledGeneratorExpression> cge = + ge.Parse(settingsPropertyValue); + + for (const std::string& config : this->Configurations) { + std::string evaluated = cge->Evaluate(this->LocalGenerator, config); + + std::vector<std::string> settings = cmExpandedList(evaluated); + for (const std::string& setting : settings) { + const std::string::size_type assignment = setting.find('='); + if (assignment != std::string::npos) { + const std::string propName = setting.substr(0, assignment); + const std::string propValue = setting.substr(assignment + 1); + + if (!propValue.empty()) { + toolSettings[config][propName] = propValue; + } + } + } + } + } +} + +bool cmVisualStudio10TargetGenerator::PropertyIsSameInAllConfigs( + const ConfigToSettings& toolSettings, const std::string& propName) +{ + std::string firstPropValue = ""; + for (const auto& configToSettings : toolSettings) { + const std::unordered_map<std::string, std::string>& settings = + configToSettings.second; + + if (firstPropValue.empty()) { + if (settings.find(propName) != settings.end()) { + firstPropValue = settings.find(propName)->second; + } + } + + if (settings.find(propName) == settings.end()) { + return false; + } + + if (settings.find(propName)->second != firstPropValue) { + return false; + } } + + return true; } void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, @@ -1789,15 +1807,6 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, { bool toolHasSettings = false; const char* tool = "None"; - std::string shaderType; - std::string shaderEntryPoint; - std::string shaderModel; - std::string shaderAdditionalFlags; - std::string shaderDisableOptimizations; - std::string shaderEnableDebug; - std::string shaderObjectFileName; - std::string outputHeaderFile; - std::string variableName; std::string settingsGenerator; std::string settingsLastGenOutput; std::string sourceLink; @@ -1805,76 +1814,84 @@ 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); - } - } + ConfigToSettings toolSettings; + for (const auto& config : this->Configurations) { + toolSettings[config]; + } + + if (this->ProjectType == csproj && !this->InSourceBuild) { + toolHasSettings = true; } if (ext == "hlsl") { tool = "FXCompile"; // Figure out the type of shader compiler to use. - if (const char* st = sf->GetProperty("VS_SHADER_TYPE")) { - shaderType = st; - toolHasSettings = true; + if (cmProp st = sf->GetProperty("VS_SHADER_TYPE")) { + for (const std::string& config : this->Configurations) { + toolSettings[config]["ShaderType"] = *st; + } } // Figure out which entry point to use if any - if (const char* se = sf->GetProperty("VS_SHADER_ENTRYPOINT")) { - shaderEntryPoint = se; - toolHasSettings = true; + if (cmProp se = sf->GetProperty("VS_SHADER_ENTRYPOINT")) { + for (const std::string& config : this->Configurations) { + toolSettings[config]["EntryPointName"] = *se; + } } // Figure out which shader model to use if any - if (const char* sm = sf->GetProperty("VS_SHADER_MODEL")) { - shaderModel = sm; - toolHasSettings = true; + if (cmProp sm = sf->GetProperty("VS_SHADER_MODEL")) { + for (const std::string& config : this->Configurations) { + toolSettings[config]["ShaderModel"] = *sm; + } } // Figure out which output header file to use if any - if (const char* ohf = sf->GetProperty("VS_SHADER_OUTPUT_HEADER_FILE")) { - outputHeaderFile = ohf; - toolHasSettings = true; + if (cmProp ohf = sf->GetProperty("VS_SHADER_OUTPUT_HEADER_FILE")) { + for (const std::string& config : this->Configurations) { + toolSettings[config]["HeaderFileOutput"] = *ohf; + } } // Figure out which variable name to use if any - if (const char* vn = sf->GetProperty("VS_SHADER_VARIABLE_NAME")) { - variableName = vn; - toolHasSettings = true; + if (cmProp vn = sf->GetProperty("VS_SHADER_VARIABLE_NAME")) { + for (const std::string& config : this->Configurations) { + toolSettings[config]["VariableName"] = *vn; + } } // Figure out if there's any additional flags to use - if (const char* saf = sf->GetProperty("VS_SHADER_FLAGS")) { - shaderAdditionalFlags = saf; - toolHasSettings = true; + if (cmProp saf = sf->GetProperty("VS_SHADER_FLAGS")) { + for (const std::string& config : this->Configurations) { + toolSettings[config]["AdditionalOptions"] = *saf; + } } // Figure out if debug information should be generated - if (const char* sed = sf->GetProperty("VS_SHADER_ENABLE_DEBUG")) { - shaderEnableDebug = sed; - toolHasSettings = true; + if (cmProp sed = sf->GetProperty("VS_SHADER_ENABLE_DEBUG")) { + cmGeneratorExpression ge; + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*sed); + + for (const std::string& config : this->Configurations) { + std::string evaluated = cge->Evaluate(this->LocalGenerator, config); + + if (!evaluated.empty()) { + toolSettings[config]["EnableDebuggingInformation"] = + cmIsOn(evaluated) ? "true" : "false"; + } + } } // Figure out if optimizations should be disabled - if (const char* sdo = sf->GetProperty("VS_SHADER_DISABLE_OPTIMIZATIONS")) { - shaderDisableOptimizations = sdo; - toolHasSettings = true; + if (cmProp sdo = sf->GetProperty("VS_SHADER_DISABLE_OPTIMIZATIONS")) { + cmGeneratorExpression ge; + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*sdo); + + for (const std::string& config : this->Configurations) { + std::string evaluated = cge->Evaluate(this->LocalGenerator, config); + + if (!evaluated.empty()) { + toolSettings[config]["DisableOptimizations"] = + cmIsOn(evaluated) ? "true" : "false"; + } + } } - if (const char* sofn = sf->GetProperty("VS_SHADER_OBJECT_FILE_NAME")) { - shaderObjectFileName = sofn; - toolHasSettings = true; + if (cmProp sofn = sf->GetProperty("VS_SHADER_OBJECT_FILE_NAME")) { + for (const std::string& config : this->Configurations) { + toolSettings[config]["ObjectFileOutput"] = *sofn; + } } } else if (ext == "jpg" || ext == "png") { tool = "Image"; @@ -1894,9 +1911,9 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, } else if (ext == "vsixmanifest") { subType = "Designer"; } - if (const char* c = sf->GetProperty("VS_COPY_TO_OUT_DIR")) { + if (cmProp c = sf->GetProperty("VS_COPY_TO_OUT_DIR")) { tool = "Content"; - copyToOutDir = c; + copyToOutDir = *c; toolHasSettings = true; } if (sf->GetPropertyAsBool("VS_INCLUDE_IN_VSIX")) { @@ -1923,32 +1940,79 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, } } - const char* toolOverride = sf->GetProperty("VS_TOOL_OVERRIDE"); - if (toolOverride && *toolOverride) { - tool = toolOverride; + cmProp toolOverride = sf->GetProperty("VS_TOOL_OVERRIDE"); + if (toolOverride && !toolOverride->empty()) { + tool = toolOverride->c_str(); } std::string deployContent; std::string deployLocation; if (this->GlobalGenerator->TargetsWindowsPhone() || this->GlobalGenerator->TargetsWindowsStore()) { - const char* content = sf->GetProperty("VS_DEPLOYMENT_CONTENT"); - if (content && *content) { + cmProp content = sf->GetProperty("VS_DEPLOYMENT_CONTENT"); + if (content && !content->empty()) { toolHasSettings = true; - deployContent = content; + deployContent = *content; - const char* location = sf->GetProperty("VS_DEPLOYMENT_LOCATION"); - if (location && *location) { - deployLocation = location; + cmProp location = sf->GetProperty("VS_DEPLOYMENT_LOCATION"); + if (location && !location->empty()) { + deployLocation = *location; } } } + if (ParsedToolTargetSettings.find(tool) == ParsedToolTargetSettings.end()) { + cmProp toolTargetProperty = this->GeneratorTarget->Target->GetProperty( + "VS_SOURCE_SETTINGS_" + std::string(tool)); + ConfigToSettings toolTargetSettings; + if (toolTargetProperty) { + ParseSettingsProperty(*toolTargetProperty, toolTargetSettings); + } + + ParsedToolTargetSettings[tool] = toolTargetSettings; + } + + for (const auto& configToSetting : ParsedToolTargetSettings[tool]) { + for (const auto& setting : configToSetting.second) { + toolSettings[configToSetting.first][setting.first] = setting.second; + } + } + + if (cmProp p = sf->GetProperty("VS_SETTINGS")) { + ParseSettingsProperty(*p, toolSettings); + } + + if (!toolSettings.empty()) { + toolHasSettings = true; + } + Elem e2(e1, tool); this->WriteSource(e2, sf); if (toolHasSettings) { e2.SetHasElements(); + std::vector<std::string> writtenSettings; + for (const auto& configSettings : toolSettings) { + for (const auto& setting : configSettings.second) { + + if (std::find(writtenSettings.begin(), writtenSettings.end(), + setting.first) != writtenSettings.end()) { + continue; + } + + if (PropertyIsSameInAllConfigs(toolSettings, setting.first)) { + e2.Element(setting.first, setting.second); + writtenSettings.push_back(setting.first); + } else { + e2.WritePlatformConfigTag(setting.first, + "'$(Configuration)|$(Platform)'=='" + + configSettings.first + "|" + + this->Platform + "'", + setting.second); + } + } + } + if (!deployContent.empty()) { cmGeneratorExpression ge; std::unique_ptr<cmCompiledGeneratorExpression> cge = @@ -1974,82 +2038,13 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, } } } - if (!shaderType.empty()) { - e2.Element("ShaderType", shaderType); - } - if (!shaderEntryPoint.empty()) { - e2.Element("EntryPointName", shaderEntryPoint); - } - if (!shaderModel.empty()) { - e2.Element("ShaderModel", shaderModel); - } - if (!outputHeaderFile.empty()) { - for (size_t i = 0; i != this->Configurations.size(); ++i) { - e2.WritePlatformConfigTag("HeaderFileOutput", - "'$(Configuration)|$(Platform)'=='" + - this->Configurations[i] + "|" + - this->Platform + "'", - outputHeaderFile); - } - } - if (!variableName.empty()) { - for (size_t i = 0; i != this->Configurations.size(); ++i) { - e2.WritePlatformConfigTag("VariableName", - "'$(Configuration)|$(Platform)'=='" + - this->Configurations[i] + "|" + - this->Platform + "'", - variableName); - } - } - if (!shaderEnableDebug.empty()) { - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = - ge.Parse(shaderEnableDebug); - - for (size_t i = 0; i != this->Configurations.size(); ++i) { - const std::string& enableDebug = - cge->Evaluate(this->LocalGenerator, this->Configurations[i]); - if (!enableDebug.empty()) { - e2.WritePlatformConfigTag("EnableDebuggingInformation", - "'$(Configuration)|$(Platform)'=='" + - this->Configurations[i] + "|" + - this->Platform + "'", - cmIsOn(enableDebug) ? "true" : "false"); - } - } - } - if (!shaderDisableOptimizations.empty()) { - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = - ge.Parse(shaderDisableOptimizations); - for (size_t i = 0; i != this->Configurations.size(); ++i) { - const std::string& disableOptimizations = - cge->Evaluate(this->LocalGenerator, this->Configurations[i]); - if (!disableOptimizations.empty()) { - e2.WritePlatformConfigTag( - "DisableOptimizations", - "'$(Configuration)|$(Platform)'=='" + this->Configurations[i] + - "|" + this->Platform + "'", - (cmIsOn(disableOptimizations) ? "true" : "false")); - } - } - } - if (!shaderObjectFileName.empty()) { - e2.Element("ObjectFileOutput", shaderObjectFileName); - } - if (!shaderAdditionalFlags.empty()) { - e2.Element("AdditionalOptions", shaderAdditionalFlags); - } if (!settingsGenerator.empty()) { e2.Element("Generator", settingsGenerator); } if (!settingsLastGenOutput.empty()) { e2.Element("LastGenOutput", settingsLastGenOutput); } - if (!sourceLink.empty()) { - e2.Element("Link", sourceLink); - } if (!subType.empty()) { e2.Element("SubType", subType); } @@ -2102,6 +2097,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); } @@ -2202,10 +2211,10 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) } } break; case cmGeneratorTarget::SourceKindResx: - // Handled elsewhere. + this->ResxObjs.push_back(si.Source); break; case cmGeneratorTarget::SourceKindXaml: - // Handled elsewhere. + this->XamlObjs.push_back(si.Source); break; } @@ -2245,7 +2254,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) e2.Attribute("CustomUnityFile", "true"); std::string unityDir = cmSystemTools::GetFilenamePath( - si.Source->GetProperty("UNITY_SOURCE_FILE")); + *si.Source->GetProperty("UNITY_SOURCE_FILE")); e2.Attribute("UnityFilesDirectory", unityDir); } else { // Visual Studio versions prior to 2017 15.8 do not know about unity @@ -2290,41 +2299,36 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( bool configDependentDefines = false; std::string includes; bool configDependentIncludes = false; - if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) { + if (cmProp cflags = sf.GetProperty("COMPILE_FLAGS")) { configDependentFlags = - cmGeneratorExpression::Find(cflags) != std::string::npos; - flags += cflags; + cmGeneratorExpression::Find(*cflags) != std::string::npos; + flags += *cflags; } - if (const char* coptions = sf.GetProperty("COMPILE_OPTIONS")) { + if (cmProp coptions = sf.GetProperty("COMPILE_OPTIONS")) { configDependentOptions = - cmGeneratorExpression::Find(coptions) != std::string::npos; - options += coptions; + cmGeneratorExpression::Find(*coptions) != std::string::npos; + options += *coptions; } - if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) { + if (cmProp cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) { configDependentDefines = - cmGeneratorExpression::Find(cdefs) != std::string::npos; - defines += cdefs; + cmGeneratorExpression::Find(*cdefs) != std::string::npos; + defines += *cdefs; } - if (const char* cincludes = sf.GetProperty("INCLUDE_DIRECTORIES")) { + if (cmProp cincludes = sf.GetProperty("INCLUDE_DIRECTORIES")) { configDependentIncludes = - cmGeneratorExpression::Find(cincludes) != std::string::npos; - includes += cincludes; + cmGeneratorExpression::Find(*cincludes) != std::string::npos; + includes += *cincludes; } - std::string lang = - this->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str()); - std::string sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf); - const std::string& linkLanguage = - this->GeneratorTarget->GetLinkerLanguage(""); - bool needForceLang = false; - // source file does not match its extension language - if (lang != sourceLang) { - needForceLang = true; - lang = sourceLang; - } - // if the source file does not match the linker language - // then force c or c++ + + // Force language if the file extension does not match. + // Note that MSVC treats the upper-case '.C' extension as C and not C++. + std::string const ext = sf.GetExtension(); + std::string const extLang = ext == "C" + ? "C" + : this->GlobalGenerator->GetLanguageFromExtension(ext.c_str()); + std::string lang = this->LocalGenerator->GetSourceFileLanguage(sf); const char* compileAs = 0; - if (needForceLang || (linkLanguage != lang)) { + if (lang != extLang) { if (lang == "CXX") { // force a C++ file type compileAs = "CompileAsCpp"; @@ -2333,6 +2337,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( compileAs = "CompileAsC"; } } + bool noWinRT = this->TargetCompileAsWinRT && lang == "C"; // for the first time we need a new line if there is something // produced here. @@ -2347,13 +2352,13 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( std::string configUpper = cmSystemTools::UpperCase(config); std::string configDefines = defines; std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper); - if (const char* ccdefs = sf.GetProperty(defPropName)) { + if (cmProp ccdefs = sf.GetProperty(defPropName)) { if (!configDefines.empty()) { configDefines += ";"; } configDependentDefines |= - cmGeneratorExpression::Find(ccdefs) != std::string::npos; - configDefines += ccdefs; + cmGeneratorExpression::Find(*ccdefs) != std::string::npos; + configDefines += *ccdefs; } // Add precompile headers compile options. @@ -2454,19 +2459,13 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } if (this->IsXamlSource(source->GetFullPath())) { const std::string& fileName = source->GetFullPath(); - std::string xamlFileName = fileName.substr(0, fileName.find_last_of(".")); - e2.Element("DependentUpon", xamlFileName); + e2.Element("DependentUpon", + fileName.substr(0, fileName.find_last_of("."))); } if (this->ProjectType == csproj) { 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()) { @@ -2504,34 +2503,34 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions( const std::string cond = this->CalcCondition(config); if (ttype <= cmStateEnums::UTILITY) { - if (const char* workingDir = this->GeneratorTarget->GetProperty( + if (cmProp workingDir = this->GeneratorTarget->GetProperty( "VS_DEBUGGER_WORKING_DIRECTORY")) { std::string genWorkingDir = cmGeneratorExpression::Evaluate( - workingDir, this->LocalGenerator, config); + *workingDir, this->LocalGenerator, config); e1.WritePlatformConfigTag("LocalDebuggerWorkingDirectory", cond, genWorkingDir); } - if (const char* environment = + if (cmProp environment = this->GeneratorTarget->GetProperty("VS_DEBUGGER_ENVIRONMENT")) { std::string genEnvironment = cmGeneratorExpression::Evaluate( - environment, this->LocalGenerator, config); + *environment, this->LocalGenerator, config); e1.WritePlatformConfigTag("LocalDebuggerEnvironment", cond, genEnvironment); } - if (const char* debuggerCommand = + if (cmProp debuggerCommand = this->GeneratorTarget->GetProperty("VS_DEBUGGER_COMMAND")) { std::string genDebuggerCommand = cmGeneratorExpression::Evaluate( - debuggerCommand, this->LocalGenerator, config); + *debuggerCommand, this->LocalGenerator, config); e1.WritePlatformConfigTag("LocalDebuggerCommand", cond, genDebuggerCommand); } - if (const char* commandArguments = this->GeneratorTarget->GetProperty( + if (cmProp commandArguments = this->GeneratorTarget->GetProperty( "VS_DEBUGGER_COMMAND_ARGUMENTS")) { std::string genCommandArguments = cmGeneratorExpression::Evaluate( - commandArguments, this->LocalGenerator, config); + *commandArguments, this->LocalGenerator, config); e1.WritePlatformConfigTag("LocalDebuggerCommandArguments", cond, genCommandArguments); } @@ -2716,7 +2715,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( std::string langForClCompile; if (this->ProjectType == csproj) { langForClCompile = "CSharp"; - } else if (cmContains(clLangs, linkLanguage)) { + } else if (cm::contains(clLangs, linkLanguage)) { langForClCompile = linkLanguage; } else { std::set<std::string> languages; @@ -2735,13 +2734,6 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, langForClCompile, configName); } - // set the correct language - if (linkLanguage == "C") { - clOptions.AddFlag("CompileAs", "CompileAsC"); - } - if (linkLanguage == "CXX") { - clOptions.AddFlag("CompileAs", "CompileAsCpp"); - } // Put the IPO enabled configurations into a set. if (this->GeneratorTarget->IsIPOEnabled(linkLanguage, configName)) { @@ -2791,9 +2783,9 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( this->Makefile->IssueMessage(MessageType::WARNING, message); } } - if (auto* clr = + if (cmProp clr = this->GeneratorTarget->GetProperty("COMMON_LANGUAGE_RUNTIME")) { - std::string clrString = clr; + std::string clrString = *clr; if (!clrString.empty()) { clrString = ":" + clrString; } @@ -2911,9 +2903,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( oh.OutputPreprocessorDefinitions(this->LangForClCompile); if (this->NsightTegra) { - if (const char* processMax = + if (cmProp processMax = this->GeneratorTarget->GetProperty("ANDROID_PROCESS_MAX")) { - e2.Element("ProcessMax", processMax); + e2.Element("ProcessMax", *processMax); } } @@ -3142,6 +3134,17 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( cudaOptions.AddIncludes(this->GetIncludes(configName, "CUDA")); cudaOptions.AddFlag("UseHostInclude", "false"); + // Add runtime library selection flag. + std::string const& cudaRuntime = + this->GeneratorTarget->GetRuntimeLinkLibrary("CUDA", configName); + if (cudaRuntime == "STATIC") { + cudaOptions.AddFlag("CudaRuntime", "Static"); + } else if (cudaRuntime == "SHARED") { + cudaOptions.AddFlag("CudaRuntime", "Shared"); + } else if (cudaRuntime == "NONE") { + cudaOptions.AddFlag("CudaRuntime", "None"); + } + this->CudaOptions[configName] = std::move(pOptions); return true; } @@ -3182,6 +3185,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions( this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable()); Options& cudaLinkOptions = *pOptions; + cmGeneratorTarget::DeviceLinkSetter setter(*this->GeneratorTarget); + // Determine if we need to do a device link const bool doDeviceLinking = requireDeviceLinking( *this->GeneratorTarget, *this->LocalGenerator, configName); @@ -3189,12 +3194,20 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions( cudaLinkOptions.AddFlag("PerformDeviceLink", doDeviceLinking ? "true" : "false"); - // Suppress deprecation warnings for default GPU targets during device link. - if (cmSystemTools::VersionCompareGreaterEq( - this->GlobalGenerator->GetPlatformToolsetCudaString(), "8.0")) { - cudaLinkOptions.AppendFlagString("AdditionalOptions", - "-Wno-deprecated-gpu-targets"); - } + // Add extra flags for device linking + cudaLinkOptions.AppendFlagString( + "AdditionalOptions", + this->Makefile->GetSafeDefinition("_CMAKE_CUDA_EXTRA_FLAGS")); + cudaLinkOptions.AppendFlagString( + "AdditionalOptions", + this->Makefile->GetSafeDefinition("_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS")); + + std::vector<std::string> linkOpts; + std::string linkFlags; + this->GeneratorTarget->GetLinkOptions(linkOpts, configName, "CUDA"); + // LINK_OPTIONS are escaped. + this->LocalGenerator->AppendCompileOptions(linkFlags, linkOpts); + cudaLinkOptions.AppendFlagString("AdditionalOptions", linkFlags); // For static libraries that have device linking enabled compute // the libraries @@ -3412,9 +3425,8 @@ void cmVisualStudio10TargetGenerator::WriteLibOptions( this->GeneratorTarget->GetLinkClosure(config)->LinkerLanguage; std::string libflags; - this->LocalGenerator->GetStaticLibraryFlags( - libflags, cmSystemTools::UpperCase(config), linkLanguage, - this->GeneratorTarget); + this->LocalGenerator->GetStaticLibraryFlags(libflags, config, linkLanguage, + this->GeneratorTarget); if (!libflags.empty()) { Elem e2(e1, "Lib"); cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; @@ -3449,7 +3461,7 @@ void cmVisualStudio10TargetGenerator::WriteManifestOptions( std::vector<cmSourceFile const*> manifest_srcs; this->GeneratorTarget->GetManifests(manifest_srcs, config); - const char* dpiAware = this->GeneratorTarget->GetProperty("VS_DPI_AWARE"); + cmProp dpiAware = this->GeneratorTarget->GetProperty("VS_DPI_AWARE"); if (!manifest_srcs.empty() || dpiAware) { Elem e2(e1, "Manifest"); @@ -3463,15 +3475,14 @@ void cmVisualStudio10TargetGenerator::WriteManifestOptions( e2.Element("AdditionalManifestFiles", oss.str()); } if (dpiAware) { - if (!strcmp(dpiAware, "PerMonitor")) { + if (*dpiAware == "PerMonitor") { e2.Element("EnableDpiAwareness", "PerMonitorHighDPIAware"); - } else if (cmIsOn(dpiAware)) { + } else if (cmIsOn(*dpiAware)) { e2.Element("EnableDpiAwareness", "true"); - } else if (cmIsOff(dpiAware)) { + } else if (cmIsOff(*dpiAware)) { e2.Element("EnableDpiAwareness", "false"); } else { - cmSystemTools::Error("Bad parameter for VS_DPI_AWARE: " + - std::string(dpiAware)); + cmSystemTools::Error("Bad parameter for VS_DPI_AWARE: " + *dpiAware); } } } @@ -3484,12 +3495,12 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( // its location as the root source directory. std::string rootDir = this->LocalGenerator->GetCurrentSourceDirectory(); { - std::vector<cmSourceFile const*> extraSources; - this->GeneratorTarget->GetExtraSources(extraSources, ""); - for (cmSourceFile const* si : extraSources) { - if ("androidmanifest.xml" == - cmSystemTools::LowerCase(si->GetLocation().GetName())) { - rootDir = si->GetLocation().GetDirectory(); + for (cmGeneratorTarget::AllConfigSource const& source : + this->GeneratorTarget->GetAllConfigSources()) { + if (source.Kind == cmGeneratorTarget::SourceKindExtra && + "androidmanifest.xml" == + cmSystemTools::LowerCase(source.Source->GetLocation().GetName())) { + rootDir = source.Source->GetLocation().GetDirectory(); break; } } @@ -3511,51 +3522,51 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( e2.Element("EnableProGuard", "true"); } - if (const char* proGuardConfigLocation = + if (cmProp proGuardConfigLocation = this->GeneratorTarget->GetProperty("ANDROID_PROGUARD_CONFIG_PATH")) { - e2.Element("ProGuardConfigLocation", proGuardConfigLocation); + e2.Element("ProGuardConfigLocation", *proGuardConfigLocation); } - if (const char* securePropertiesLocation = + if (cmProp securePropertiesLocation = this->GeneratorTarget->GetProperty("ANDROID_SECURE_PROPS_PATH")) { - e2.Element("SecurePropertiesLocation", securePropertiesLocation); + e2.Element("SecurePropertiesLocation", *securePropertiesLocation); } - if (const char* nativeLibDirectoriesExpression = + if (cmProp nativeLibDirectoriesExpression = this->GeneratorTarget->GetProperty("ANDROID_NATIVE_LIB_DIRECTORIES")) { std::string nativeLibDirs = cmGeneratorExpression::Evaluate( - nativeLibDirectoriesExpression, this->LocalGenerator, configName); + *nativeLibDirectoriesExpression, this->LocalGenerator, configName); e2.Element("NativeLibDirectories", nativeLibDirs); } - if (const char* nativeLibDependenciesExpression = + if (cmProp nativeLibDependenciesExpression = this->GeneratorTarget->GetProperty( "ANDROID_NATIVE_LIB_DEPENDENCIES")) { std::string nativeLibDeps = cmGeneratorExpression::Evaluate( - nativeLibDependenciesExpression, this->LocalGenerator, configName); + *nativeLibDependenciesExpression, this->LocalGenerator, configName); e2.Element("NativeLibDependencies", nativeLibDeps); } - if (const char* javaSourceDir = + if (cmProp javaSourceDir = this->GeneratorTarget->GetProperty("ANDROID_JAVA_SOURCE_DIR")) { - e2.Element("JavaSourceDir", javaSourceDir); + e2.Element("JavaSourceDir", *javaSourceDir); } - if (const char* jarDirectoriesExpression = + if (cmProp jarDirectoriesExpression = this->GeneratorTarget->GetProperty("ANDROID_JAR_DIRECTORIES")) { std::string jarDirectories = cmGeneratorExpression::Evaluate( - jarDirectoriesExpression, this->LocalGenerator, configName); + *jarDirectoriesExpression, this->LocalGenerator, configName); e2.Element("JarDirectories", jarDirectories); } - if (const char* jarDeps = + if (cmProp jarDeps = this->GeneratorTarget->GetProperty("ANDROID_JAR_DEPENDENCIES")) { - e2.Element("JarDependencies", jarDeps); + e2.Element("JarDependencies", *jarDeps); } - if (const char* assetsDirectories = + if (cmProp assetsDirectories = this->GeneratorTarget->GetProperty("ANDROID_ASSETS_DIRECTORIES")) { - e2.Element("AssetsDirectories", assetsDirectories); + e2.Element("AssetsDirectories", *assetsDirectories); } { @@ -3564,10 +3575,10 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions( e2.Element("AndroidManifestLocation", manifest_xml); } - if (const char* antAdditionalOptions = + if (cmProp antAdditionalOptions = this->GeneratorTarget->GetProperty("ANDROID_ANT_ADDITIONAL_OPTIONS")) { e2.Element("AdditionalOptions", - std::string(antAdditionalOptions) + " %(AdditionalOptions)"); + *antAdditionalOptions + " %(AdditionalOptions)"); } } @@ -3619,17 +3630,15 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG; flags += " "; flags += this->Makefile->GetRequiredDefinition(linkFlagVar); - const char* targetLinkFlags = - this->GeneratorTarget->GetProperty("LINK_FLAGS"); + cmProp targetLinkFlags = this->GeneratorTarget->GetProperty("LINK_FLAGS"); if (targetLinkFlags) { flags += " "; - flags += targetLinkFlags; + flags += *targetLinkFlags; } std::string flagsProp = cmStrCat("LINK_FLAGS_", CONFIG); - if (const char* flagsConfig = - this->GeneratorTarget->GetProperty(flagsProp)) { + if (cmProp flagsConfig = this->GeneratorTarget->GetProperty(flagsProp)) { flags += " "; - flags += flagsConfig; + flags += *flagsConfig; } std::vector<std::string> opts; @@ -3650,10 +3659,6 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions( std::vector<std::string> libVec; std::vector<std::string> vsTargetVec; this->AddLibraries(cli, libVec, vsTargetVec, config); - if (cmContains(linkClosure->Languages, "CUDA") && - this->CudaOptions[config] != nullptr) { - this->CudaOptions[config]->FixCudaRuntime(this->GeneratorTarget); - } std::string standardLibsVar = cmStrCat("CMAKE_", linkLanguage, "_STANDARD_LIBRARIES"); std::string const& libs = this->Makefile->GetSafeDefinition(standardLibsVar); @@ -3924,7 +3929,7 @@ void cmVisualStudio10TargetGenerator::AddTargetsFileAndConfigPair( { for (TargetsFileAndConfigs& i : this->TargetsFileAndConfigsVec) { if (cmSystemTools::ComparePath(targetsFile, i.File)) { - if (!cmContains(i.Configs, config)) { + if (!cm::contains(i.Configs, config)) { i.Configs.push_back(config); } return; @@ -4052,6 +4057,7 @@ void cmVisualStudio10TargetGenerator::WriteEvent( std::string script; const char* pre = ""; std::string comment; + bool stdPipesUTF8 = false; for (cmCustomCommand const& cc : commands) { cmCustomCommandGenerator ccg(cc, configName, lg); if (!ccg.HasOnlyEmptyCommandLines()) { @@ -4060,11 +4066,16 @@ void cmVisualStudio10TargetGenerator::WriteEvent( script += pre; pre = "\n"; script += lg->ConstructScript(ccg); + + stdPipesUTF8 = stdPipesUTF8 || cc.GetStdPipesUTF8(); } } comment = cmVS10EscapeComment(comment); if (this->ProjectType != csproj) { Elem e2(e1, name); + if (stdPipesUTF8) { + this->WriteStdOutEncodingUtf8(e2); + } e2.Element("Message", comment); e2.Element("Command", script); } else { @@ -4102,9 +4113,9 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0) cmLocalGenerator* lg = dt->GetLocalGenerator(); std::string name = dt->GetName(); std::string path; - const char* p = dt->GetProperty("EXTERNAL_MSPROJECT"); + cmProp p = dt->GetProperty("EXTERNAL_MSPROJECT"); if (p) { - path = p; + path = *p; } else { path = cmStrCat(lg->GetCurrentBinaryDirectory(), '/', dt->GetName(), computeProjectFileExtension(dt)); @@ -4120,7 +4131,8 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0) } // Don't reference targets that don't produce any output. - if (dt->GetManagedType("") == cmGeneratorTarget::ManagedType::Undefined) { + if (dt->GetManagedType(this->Configurations[0]) == + cmGeneratorTarget::ManagedType::Undefined) { e2.Element("ReferenceOutputAssembly", "false"); e2.Element("CopyToOutputDirectory", "Never"); } @@ -4132,17 +4144,17 @@ void cmVisualStudio10TargetGenerator::WritePlatformExtensions(Elem& e1) // This only applies to Windows 10 apps if (this->GlobalGenerator->TargetsWindowsStore() && cmHasLiteralPrefix(this->GlobalGenerator->GetSystemVersion(), "10.0")) { - const char* desktopExtensionsVersion = + cmProp desktopExtensionsVersion = this->GeneratorTarget->GetProperty("VS_DESKTOP_EXTENSIONS_VERSION"); if (desktopExtensionsVersion) { this->WriteSinglePlatformExtension(e1, "WindowsDesktop", - desktopExtensionsVersion); + *desktopExtensionsVersion); } - const char* mobileExtensionsVersion = + cmProp mobileExtensionsVersion = this->GeneratorTarget->GetProperty("VS_MOBILE_EXTENSIONS_VERSION"); if (mobileExtensionsVersion) { this->WriteSinglePlatformExtension(e1, "WindowsMobile", - mobileExtensionsVersion); + *mobileExtensionsVersion); } } } @@ -4167,9 +4179,9 @@ void cmVisualStudio10TargetGenerator::WriteSDKReferences(Elem& e0) { std::vector<std::string> sdkReferences; std::unique_ptr<Elem> spe1; - if (const char* vsSDKReferences = + if (cmProp vsSDKReferences = this->GeneratorTarget->GetProperty("VS_SDK_REFERENCES")) { - cmExpandList(vsSDKReferences, sdkReferences); + cmExpandList(*vsSDKReferences, sdkReferences); spe1 = cm::make_unique<Elem>(e0, "ItemGroup"); for (std::string const& ri : sdkReferences) { Elem(*spe1, "SDKReference").Attribute("Include", ri); @@ -4179,11 +4191,11 @@ void cmVisualStudio10TargetGenerator::WriteSDKReferences(Elem& e0) // This only applies to Windows 10 apps if (this->GlobalGenerator->TargetsWindowsStore() && cmHasLiteralPrefix(this->GlobalGenerator->GetSystemVersion(), "10.0")) { - const char* desktopExtensionsVersion = + cmProp desktopExtensionsVersion = this->GeneratorTarget->GetProperty("VS_DESKTOP_EXTENSIONS_VERSION"); - const char* mobileExtensionsVersion = + cmProp mobileExtensionsVersion = this->GeneratorTarget->GetProperty("VS_MOBILE_EXTENSIONS_VERSION"); - const char* iotExtensionsVersion = + cmProp iotExtensionsVersion = this->GeneratorTarget->GetProperty("VS_IOT_EXTENSIONS_VERSION"); if (desktopExtensionsVersion || mobileExtensionsVersion || @@ -4193,15 +4205,15 @@ void cmVisualStudio10TargetGenerator::WriteSDKReferences(Elem& e0) } if (desktopExtensionsVersion) { this->WriteSingleSDKReference(*spe1, "WindowsDesktop", - desktopExtensionsVersion); + *desktopExtensionsVersion); } if (mobileExtensionsVersion) { this->WriteSingleSDKReference(*spe1, "WindowsMobile", - mobileExtensionsVersion); + *mobileExtensionsVersion); } if (iotExtensionsVersion) { this->WriteSingleSDKReference(*spe1, "WindowsIoT", - iotExtensionsVersion); + *iotExtensionsVersion); } } } @@ -4221,12 +4233,13 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile( this->GlobalGenerator->TargetsWindowsPhone()) && (cmStateEnums::EXECUTABLE == this->GeneratorTarget->GetType())) { std::string pfxFile; - std::vector<cmSourceFile const*> certificates; - this->GeneratorTarget->GetCertificates(certificates, ""); - for (cmSourceFile const* si : certificates) { - pfxFile = this->ConvertPath(si->GetFullPath(), false); - ConvertToWindowsSlash(pfxFile); - break; + for (cmGeneratorTarget::AllConfigSource const& source : + this->GeneratorTarget->GetAllConfigSources()) { + if (source.Kind == cmGeneratorTarget::SourceKindCertificate) { + pfxFile = this->ConvertPath(source.Source->GetFullPath(), false); + ConvertToWindowsSlash(pfxFile); + break; + } } if (this->IsMissingFiles && @@ -4272,28 +4285,61 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile( } } +void cmVisualStudio10TargetGenerator::ClassifyAllConfigSources() +{ + for (cmGeneratorTarget::AllConfigSource const& source : + this->GeneratorTarget->GetAllConfigSources()) { + this->ClassifyAllConfigSource(source); + } +} + +void cmVisualStudio10TargetGenerator::ClassifyAllConfigSource( + cmGeneratorTarget::AllConfigSource const& acs) +{ + switch (acs.Kind) { + case cmGeneratorTarget::SourceKindResx: { + // Build and save the name of the corresponding .h file + // This relationship will be used later when building the project files. + // Both names would have been auto generated from Visual Studio + // where the user supplied the file name and Visual Studio + // appended the suffix. + std::string resx = acs.Source->ResolveFullPath(); + std::string hFileName = resx.substr(0, resx.find_last_of('.')) + ".h"; + this->ExpectedResxHeaders.insert(hFileName); + } break; + case cmGeneratorTarget::SourceKindXaml: { + // Build and save the name of the corresponding .h and .cpp file + // This relationship will be used later when building the project files. + // Both names would have been auto generated from Visual Studio + // where the user supplied the file name and Visual Studio + // appended the suffix. + std::string xaml = acs.Source->ResolveFullPath(); + std::string hFileName = xaml + ".h"; + std::string cppFileName = xaml + ".cpp"; + this->ExpectedXamlHeaders.insert(hFileName); + this->ExpectedXamlSources.insert(cppFileName); + } break; + default: + break; + } +} + bool cmVisualStudio10TargetGenerator::IsResxHeader( const std::string& headerFile) { - std::set<std::string> expectedResxHeaders; - this->GeneratorTarget->GetExpectedResxHeaders(expectedResxHeaders, ""); - return expectedResxHeaders.count(headerFile) > 0; + return this->ExpectedResxHeaders.count(headerFile) > 0; } bool cmVisualStudio10TargetGenerator::IsXamlHeader( const std::string& headerFile) { - std::set<std::string> expectedXamlHeaders; - this->GeneratorTarget->GetExpectedXamlHeaders(expectedXamlHeaders, ""); - return expectedXamlHeaders.count(headerFile) > 0; + return this->ExpectedXamlHeaders.count(headerFile) > 0; } bool cmVisualStudio10TargetGenerator::IsXamlSource( const std::string& sourceFile) { - std::set<std::string> expectedXamlSources; - this->GeneratorTarget->GetExpectedXamlSources(expectedXamlSources, ""); - return expectedXamlSources.count(sourceFile) > 0; + return this->ExpectedXamlSources.count(sourceFile) > 0; } void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1) @@ -4352,10 +4398,10 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1) if (!targetPlatformVersion.empty()) { e1.Element("WindowsTargetPlatformVersion", targetPlatformVersion); } - const char* targetPlatformMinVersion = this->GeneratorTarget->GetProperty( + cmProp targetPlatformMinVersion = this->GeneratorTarget->GetProperty( "VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION"); if (targetPlatformMinVersion) { - e1.Element("WindowsTargetPlatformMinVersion", targetPlatformMinVersion); + e1.Element("WindowsTargetPlatformMinVersion", *targetPlatformMinVersion); } else if (isWindowsStore && rev == "10.0") { // If the min version is not set, then use the TargetPlatformVersion if (!targetPlatformVersion.empty()) { @@ -4374,39 +4420,38 @@ void cmVisualStudio10TargetGenerator::VerifyNecessaryFiles() // For Windows and Windows Phone executables, we will assume that if a // manifest is not present that we need to add all the necessary files if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) { - std::vector<cmSourceFile const*> manifestSources; - this->GeneratorTarget->GetAppManifest(manifestSources, ""); - { - std::string const& v = this->GlobalGenerator->GetSystemVersion(); - if (this->GlobalGenerator->TargetsWindowsPhone()) { - if (v == "8.0") { - // Look through the sources for WMAppManifest.xml - std::vector<cmSourceFile const*> extraSources; - this->GeneratorTarget->GetExtraSources(extraSources, ""); - bool foundManifest = false; - for (cmSourceFile const* si : extraSources) { - // Need to do a lowercase comparison on the filename - if ("wmappmanifest.xml" == - cmSystemTools::LowerCase(si->GetLocation().GetName())) { - foundManifest = true; - break; - } - } - if (!foundManifest) { - this->IsMissingFiles = true; - } - } else if (v == "8.1") { - if (manifestSources.empty()) { - this->IsMissingFiles = true; + std::vector<cmGeneratorTarget::AllConfigSource> manifestSources = + this->GeneratorTarget->GetAllConfigSources( + cmGeneratorTarget::SourceKindAppManifest); + std::string const& v = this->GlobalGenerator->GetSystemVersion(); + if (this->GlobalGenerator->TargetsWindowsPhone()) { + if (v == "8.0") { + // Look through the sources for WMAppManifest.xml + bool foundManifest = false; + for (cmGeneratorTarget::AllConfigSource const& source : + this->GeneratorTarget->GetAllConfigSources()) { + if (source.Kind == cmGeneratorTarget::SourceKindExtra && + "wmappmanifest.xml" == + cmSystemTools::LowerCase( + source.Source->GetLocation().GetName())) { + foundManifest = true; + break; } } - } else if (this->GlobalGenerator->TargetsWindowsStore()) { + if (!foundManifest) { + this->IsMissingFiles = true; + } + } else if (v == "8.1") { if (manifestSources.empty()) { - if (v == "8.0") { - this->IsMissingFiles = true; - } else if (v == "8.1" || cmHasLiteralPrefix(v, "10.0")) { - this->IsMissingFiles = true; - } + this->IsMissingFiles = true; + } + } + } else if (this->GlobalGenerator->TargetsWindowsStore()) { + if (manifestSources.empty()) { + if (v == "8.0") { + this->IsMissingFiles = true; + } else if (v == "8.1" || cmHasLiteralPrefix(v, "10.0")) { + this->IsMissingFiles = true; } } } @@ -4845,11 +4890,11 @@ void cmVisualStudio10TargetGenerator::GetCSharpSourceProperties( if (this->ProjectType == csproj) { const cmPropertyMap& props = sf->GetProperties(); for (const std::string& p : props.GetKeys()) { - static const std::string propNamePrefix = "VS_CSHARP_"; - if (p.find(propNamePrefix) == 0) { + static const cm::string_view propNamePrefix = "VS_CSHARP_"; + if (cmHasPrefix(p, propNamePrefix)) { std::string tagName = p.substr(propNamePrefix.length()); if (!tagName.empty()) { - const std::string val = props.GetPropertyValue(p); + const std::string& val = *props.GetPropertyValue(p); if (!val.empty()) { tags[tagName] = val; } else { @@ -4869,24 +4914,34 @@ void cmVisualStudio10TargetGenerator::WriteCSharpSourceProperties( } } -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 (cmHasPrefix(fullFileName, srcDir)) { + link = fullFileName.substr(srcDir.length() + 1); + } else if (cmHasPrefix(fullFileName, binDir)) { + link = fullFileName.substr(binDir.length() + 1); + } else if (cmProp l = source->GetProperty("VS_CSHARP_Link")) { + link = *l; + } + + ConvertToWindowsSlash(link); + return link; } std::string cmVisualStudio10TargetGenerator::GetCMakeFilePath( @@ -4899,3 +4954,10 @@ std::string cmVisualStudio10TargetGenerator::GetCMakeFilePath( return path; } + +void cmVisualStudio10TargetGenerator::WriteStdOutEncodingUtf8(Elem& e1) +{ + if (this->GlobalGenerator->IsStdOutEncodingSupported()) { + e1.Element("StdOutEncoding", "UTF-8"); + } +} diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 30027c9e7..7c71de3dc 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -10,12 +10,14 @@ #include <memory> #include <set> #include <string> +#include <unordered_map> #include <vector> +#include "cmGeneratorTarget.h" + class cmComputeLinkInformation; class cmCustomCommand; class cmGeneratedFileStream; -class cmGeneratorTarget; class cmGlobalVisualStudio10Generator; class cmLocalVisualStudio10Generator; class cmMakefile; @@ -73,8 +75,6 @@ private: std::vector<size_t> const& exclude_configs); void WriteAllSources(Elem& e0); void WritePackageReferences(Elem& e0); - void WritePackageReference(Elem& e1, std::string const& ref, - std::string const& version); void WriteDotNetReferences(Elem& e0); void WriteDotNetReference(Elem& e1, std::string const& ref, std::string const& hint, @@ -183,7 +183,9 @@ 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); + + void WriteStdOutEncodingUtf8(Elem& e1); private: friend class cmVS10GeneratorOptions; @@ -236,6 +238,23 @@ private: using ToolSourceMap = std::map<std::string, ToolSources>; ToolSourceMap Tools; + + std::set<std::string> ExpectedResxHeaders; + std::set<std::string> ExpectedXamlHeaders; + std::set<std::string> ExpectedXamlSources; + std::vector<cmSourceFile const*> ResxObjs; + std::vector<cmSourceFile const*> XamlObjs; + void ClassifyAllConfigSources(); + void ClassifyAllConfigSource(cmGeneratorTarget::AllConfigSource const& acs); + + using ConfigToSettings = + std::unordered_map<std::string, + std::unordered_map<std::string, std::string>>; + std::unordered_map<std::string, ConfigToSettings> ParsedToolTargetSettings; + bool PropertyIsSameInAllConfigs(const ConfigToSettings& toolSettings, + const std::string& propName); + void ParseSettingsProperty(const std::string& settingsPropertyValue, + ConfigToSettings& toolSettings); std::string GetCMakeFilePath(const char* name) const; }; diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index 4004b6648..937b4ce4a 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -151,35 +151,6 @@ bool cmVisualStudioGeneratorOptions::UsingSBCS() const return false; } -void cmVisualStudioGeneratorOptions::FixCudaRuntime(cmGeneratorTarget* target) -{ - std::map<std::string, FlagValue>::const_iterator i = - this->FlagMap.find("CudaRuntime"); - if (i == this->FlagMap.end()) { - // User didn't provide am override so get the property value - 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"); - } - } -} - void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() { // Extract temporary values stored by our flag table. diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index b335694f2..f9b50a7a3 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -63,7 +63,6 @@ public: bool UsingSBCS() const; void FixCudaCodeGeneration(); - void FixCudaRuntime(cmGeneratorTarget* target); void FixManifestUACFlags(); diff --git a/Source/cmVisualStudioSlnParser.cxx b/Source/cmVisualStudioSlnParser.cxx index 4533e9b69..d7822b14d 100644 --- a/Source/cmVisualStudioSlnParser.cxx +++ b/Source/cmVisualStudioSlnParser.cxx @@ -517,7 +517,7 @@ bool cmVisualStudioSlnParser::ParseMultiValueTag(const std::string& line, State& state) { size_t idxEqualSign = line.find('='); - const std::string& fullTag = line.substr(0, idxEqualSign); + auto fullTag = cm::string_view(line).substr(0, idxEqualSign); if (!this->ParseTag(fullTag, parsedLine, state)) return false; if (idxEqualSign != line.npos) { @@ -560,7 +560,7 @@ bool cmVisualStudioSlnParser::ParseSingleValueTag(const std::string& line, State& state) { size_t idxEqualSign = line.find('='); - const std::string& fullTag = line.substr(0, idxEqualSign); + auto fullTag = cm::string_view(line).substr(0, idxEqualSign); if (!this->ParseTag(fullTag, parsedLine, state)) return false; if (idxEqualSign != line.npos) { @@ -586,17 +586,17 @@ bool cmVisualStudioSlnParser::ParseKeyValuePair(const std::string& line, return true; } -bool cmVisualStudioSlnParser::ParseTag(const std::string& fullTag, +bool cmVisualStudioSlnParser::ParseTag(cm::string_view fullTag, ParsedLine& parsedLine, State& state) { size_t idxLeftParen = fullTag.find('('); - if (idxLeftParen == fullTag.npos) { + if (idxLeftParen == cm::string_view::npos) { parsedLine.SetTag(cmTrimWhitespace(fullTag)); return true; } parsedLine.SetTag(cmTrimWhitespace(fullTag.substr(0, idxLeftParen))); size_t idxRightParen = fullTag.rfind(')'); - if (idxRightParen == fullTag.npos) { + if (idxRightParen == cm::string_view::npos) { this->LastResult.SetError(ResultErrorInputStructure, state.GetCurrentLine()); return false; diff --git a/Source/cmVisualStudioSlnParser.h b/Source/cmVisualStudioSlnParser.h index 6c05633b8..4557cdb10 100644 --- a/Source/cmVisualStudioSlnParser.h +++ b/Source/cmVisualStudioSlnParser.h @@ -9,6 +9,8 @@ #include <iosfwd> #include <string> +#include <cm/string_view> + #include <stddef.h> class cmSlnData; @@ -97,8 +99,7 @@ protected: bool ParseKeyValuePair(const std::string& line, ParsedLine& parsedLine, State& state); - bool ParseTag(const std::string& fullTag, ParsedLine& parsedLine, - State& state); + bool ParseTag(cm::string_view fullTag, ParsedLine& parsedLine, State& state); bool ParseValue(const std::string& value, ParsedLine& parsedLine); }; diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 26e7c7537..0d8e894f8 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -7,8 +7,7 @@ #include <cm/memory> #include <cm/string_view> - -#include "cm_static_string_view.hxx" +#include <cmext/string_view> #include "cmConditionEvaluator.h" #include "cmExecutionStatus.h" diff --git a/Source/cmWorkerPool.cxx b/Source/cmWorkerPool.cxx index aa0d6b3d5..12aba4f96 100644 --- a/Source/cmWorkerPool.cxx +++ b/Source/cmWorkerPool.cxx @@ -13,7 +13,7 @@ #include <cm/memory> -#include "cm_uv.h" +#include <cm3p/uv.h> #include "cmRange.h" #include "cmStringAlgorithms.h" @@ -469,11 +469,9 @@ void cmWorkerPoolWorker::UVProcessStart(uv_async_t* handle) void cmWorkerPoolWorker::UVProcessFinished() { - { - std::lock_guard<std::mutex> lock(Proc_.Mutex); - if (Proc_.ROP && (Proc_.ROP->IsFinished() || !Proc_.ROP->IsStarted())) { - Proc_.ROP.reset(); - } + std::lock_guard<std::mutex> lock(Proc_.Mutex); + if (Proc_.ROP && (Proc_.ROP->IsFinished() || !Proc_.ROP->IsStarted())) { + Proc_.ROP.reset(); } // Notify idling thread Proc_.Condition.notify_one(); @@ -532,6 +530,7 @@ public: unsigned int JobsProcessing = 0; std::deque<cmWorkerPool::JobHandleT> Queue; std::condition_variable Condition; + std::condition_variable ConditionFence; std::vector<std::unique_ptr<cmWorkerPoolWorker>> Workers; // -- References @@ -593,19 +592,12 @@ bool cmWorkerPoolInternal::Process() void cmWorkerPoolInternal::Abort() { - bool notifyThreads = false; // Clear all jobs and set abort flag - { - std::lock_guard<std::mutex> guard(Mutex); - if (Processing && !Aborting) { - // Register abort and clear queue - Aborting = true; - Queue.clear(); - notifyThreads = true; - } - } - if (notifyThreads) { - // Wake threads + std::lock_guard<std::mutex> guard(Mutex); + if (!Aborting) { + // Register abort and clear queue + Aborting = true; + Queue.clear(); Condition.notify_all(); } } @@ -669,7 +661,7 @@ void cmWorkerPoolInternal::Work(unsigned int workerIndex) if (Aborting) { break; } - // Wait for new jobs + // Wait for new jobs on the main CV if (Queue.empty()) { ++WorkersIdle; Condition.wait(uLock); @@ -677,20 +669,34 @@ void cmWorkerPoolInternal::Work(unsigned int workerIndex) continue; } - // Check for fence jobs - if (FenceProcessing || Queue.front()->IsFence()) { - if (JobsProcessing != 0) { - Condition.wait(uLock); - continue; - } - // No jobs get processed. Set the fence job processing flag. - FenceProcessing = true; + // If there is a fence currently active or waiting, + // sleep on the main CV and try again. + if (FenceProcessing) { + Condition.wait(uLock); + continue; } // Pop next job from queue jobHandle = std::move(Queue.front()); Queue.pop_front(); + // Check for fence jobs + bool raisedFence = false; + if (jobHandle->IsFence()) { + FenceProcessing = true; + raisedFence = true; + // Wait on the Fence CV until all pending jobs are done. + while (JobsProcessing != 0 && !Aborting) { + ConditionFence.wait(uLock); + } + // When aborting, explicitly kick all threads alive once more. + if (Aborting) { + FenceProcessing = false; + Condition.notify_all(); + break; + } + } + // Unlocked scope for job processing ++JobsProcessing; { @@ -701,11 +707,18 @@ void cmWorkerPoolInternal::Work(unsigned int workerIndex) } --JobsProcessing; - // Was this a fence job? - if (FenceProcessing) { + // If this was the thread that entered fence processing + // originally, notify all idling workers that the fence + // is done. + if (raisedFence) { FenceProcessing = false; Condition.notify_all(); } + // If fence processing is still not done, notify the + // the fencing worker when all active jobs are done. + if (FenceProcessing && JobsProcessing == 0) { + ConditionFence.notify_all(); + } } // Decrement running workers count diff --git a/Source/cmWorkingDirectory.h b/Source/cmWorkingDirectory.h index d4a164de6..4c7576de5 100644 --- a/Source/cmWorkingDirectory.h +++ b/Source/cmWorkingDirectory.h @@ -37,6 +37,8 @@ public: */ int GetLastResult() const { return ResultCode; } + std::string const& GetOldDirectory() const { return this->OldDir; } + private: std::string OldDir; int ResultCode; diff --git a/Source/cmWriteFileCommand.cxx b/Source/cmWriteFileCommand.cxx index 34e21b2f2..666ba8769 100644 --- a/Source/cmWriteFileCommand.cxx +++ b/Source/cmWriteFileCommand.cxx @@ -72,7 +72,7 @@ bool cmWriteFileCommand(std::vector<std::string> const& args, status.SetError(error); return false; } - file << message << std::endl; + file << message << '\n'; file.close(); if (mode && !writable) { cmSystemTools::SetPermissions(fileName.c_str(), mode); diff --git a/Source/cmXCode21Object.cxx b/Source/cmXCode21Object.cxx index a9bb2ef54..6b133a9e8 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 8e4b80fc1..76fad23fd 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/cmXCodeObject.h b/Source/cmXCodeObject.h index d9be3d2db..24ecaa22c 100644 --- a/Source/cmXCodeObject.h +++ b/Source/cmXCodeObject.h @@ -12,7 +12,7 @@ #include <utility> #include <vector> -#include "cmAlgorithms.h" +#include <cmext/algorithm> class cmGeneratorTarget; @@ -82,10 +82,13 @@ public: void SetObject(cmXCodeObject* value) { this->Object = value; } cmXCodeObject* GetObject() { return this->Object; } void AddObject(cmXCodeObject* value) { this->List.push_back(value); } - bool HasObject(cmXCodeObject* o) const { return cmContains(this->List, o); } + bool HasObject(cmXCodeObject* o) const + { + return cm::contains(this->List, o); + } void AddUniqueObject(cmXCodeObject* value) { - if (!cmContains(this->List, value)) { + if (!cm::contains(this->List, value)) { this->List.push_back(value); } } diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx index b34c2f6e1..f4c2f2d4c 100644 --- a/Source/cmXCodeScheme.cxx +++ b/Source/cmXCodeScheme.cxx @@ -7,6 +7,8 @@ #include <sstream> #include <utility> +#include <cmext/algorithm> + #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" @@ -202,14 +204,14 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout, // Info tab begin - if (const char* exe = + if (cmProp exe = this->Target->GetTarget()->GetProperty("XCODE_SCHEME_EXECUTABLE")) { xout.StartElement("PathRunnable"); xout.BreakAttributes(); xout.Attribute("runnableDebuggingMode", "0"); - xout.Attribute("FilePath", exe); + xout.Attribute("FilePath", *exe); xout.EndElement(); // PathRunnable } @@ -218,9 +220,9 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout, // Arguments tab begin - if (const char* argList = + if (cmProp argList = this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ARGUMENTS")) { - std::vector<std::string> arguments = cmExpandedList(argList); + std::vector<std::string> arguments = cmExpandedList(*argList); if (!arguments.empty()) { xout.StartElement("CommandLineArguments"); @@ -238,9 +240,9 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout, } } - if (const char* envList = + if (cmProp envList = this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ENVIRONMENT")) { - std::vector<std::string> envs = cmExpandedList(envList); + std::vector<std::string> envs = cmExpandedList(*envList); if (!envs.empty()) { xout.StartElement("EnvironmentVariables"); @@ -321,8 +323,9 @@ bool cmXCodeScheme::WriteLaunchActionBooleanAttribute( cmXMLWriter& xout, const std::string& attrName, const std::string& varName, bool defaultValue) { - auto property = Target->GetTarget()->GetProperty(varName); - bool isOn = (property == nullptr && defaultValue) || cmIsOn(property); + cmProp property = Target->GetTarget()->GetProperty(varName); + bool isOn = + (property == nullptr && defaultValue) || (property && cmIsOn(*property)); if (isOn) { xout.Attribute(attrName.c_str(), "YES"); @@ -393,7 +396,8 @@ void cmXCodeScheme::WriteBuildableReference(cmXMLWriter& xout, xout.BreakAttributes(); xout.Attribute("BuildableIdentifier", "primary"); xout.Attribute("BlueprintIdentifier", xcObj->GetId()); - xout.Attribute("BuildableName", xcObj->GetTarget()->GetFullName()); + std::string const noConfig; // FIXME: What config to use here? + xout.Attribute("BuildableName", xcObj->GetTarget()->GetFullName(noConfig)); xout.Attribute("BlueprintName", xcObj->GetTarget()->GetName()); xout.Attribute("ReferencedContainer", "container:" + container); xout.EndElement(); @@ -402,8 +406,9 @@ void cmXCodeScheme::WriteBuildableReference(cmXMLWriter& xout, void cmXCodeScheme::WriteCustomWorkingDirectory( cmXMLWriter& xout, const std::string& configuration) { - std::string propertyValue = this->Target->GetTarget()->GetSafeProperty( - "XCODE_SCHEME_WORKING_DIRECTORY"); + std::string const& propertyValue = + this->Target->GetTarget()->GetSafeProperty( + "XCODE_SCHEME_WORKING_DIRECTORY"); if (propertyValue.empty()) { xout.Attribute("useCustomWorkingDirectory", "NO"); } else { @@ -427,7 +432,7 @@ std::string cmXCodeScheme::FindConfiguration(const std::string& name) // Try to find the desired configuration by name, // and if it's not found return first from the list // - if (!cmContains(this->ConfigList, name) && !this->ConfigList.empty()) { + if (!cm::contains(this->ConfigList, name) && !this->ConfigList.empty()) { return this->ConfigList[0]; } diff --git a/Source/cmXMLParser.cxx b/Source/cmXMLParser.cxx index ad5c4ba28..24da8c60e 100644 --- a/Source/cmXMLParser.cxx +++ b/Source/cmXMLParser.cxx @@ -7,9 +7,9 @@ #include <iostream> #include <sstream> -#include "cmsys/FStream.hxx" +#include <cm3p/expat.h> -#include "cm_expat.h" +#include "cmsys/FStream.hxx" cmXMLParser::cmXMLParser() { diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h index bc445aa5b..00ea08cef 100644 --- a/Source/cmXMLWriter.h +++ b/Source/cmXMLWriter.h @@ -6,7 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <chrono> -#include <cstddef> +#include <cstddef> // IWYU pragma: keep #include <ctime> #include <ostream> #include <stack> diff --git a/Source/cm_get_date.c b/Source/cm_get_date.c index 4bef80315..49f55772b 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/cm_static_string_view.hxx b/Source/cm_static_string_view.hxx deleted file mode 100644 index 708ac9579..000000000 --- a/Source/cm_static_string_view.hxx +++ /dev/null @@ -1,41 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cm_static_string_view_hxx -#define cm_static_string_view_hxx - -#include "cmConfigure.h" // IWYU pragma: keep - -#include <cstddef> - -#include <cm/string_view> - -namespace cm { - -/** A string_view that only binds to static storage. - * - * This is used together with the `""_s` user-defined literal operator - * to construct a type-safe abstraction of a string_view that only views - * statically allocated strings. These strings are const and available - * for the entire lifetime of the program. - */ -class static_string_view : public string_view -{ - static_string_view(string_view v) - : string_view(v) - { - } - - friend static_string_view operator"" _s(const char* data, size_t size); -}; - -/** Create a static_string_view using `""_s` literal syntax. */ -inline static_string_view operator"" _s(const char* data, size_t size) -{ - return string_view(data, size); -} - -} // namespace cm - -using cm::operator"" _s; - -#endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index a99d9a633..162e807f1 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -9,6 +9,7 @@ #include <initializer_list> #include <iostream> #include <sstream> +#include <stdexcept> #include <utility> #include <cm/memory> @@ -18,6 +19,7 @@ #endif #include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" @@ -25,7 +27,6 @@ #include "cm_sys_stat.h" -#include "cmAlgorithms.h" #include "cmCommands.h" #include "cmDocumentation.h" #include "cmDocumentationEntry.h" @@ -39,6 +40,9 @@ #include "cmLinkLineComputer.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#if !defined(CMAKE_BOOTSTRAP) +# include "cmMakefileProfilingData.h" +#endif #include "cmMessenger.h" #include "cmState.h" #include "cmStateDirectory.h" @@ -53,7 +57,7 @@ #if !defined(CMAKE_BOOTSTRAP) # include <unordered_map> -# include "cm_jsoncpp_writer.h" +# include <cm3p/json/writer.h> # include "cmFileAPI.h" # include "cmGraphVizWriter.h" @@ -134,6 +138,7 @@ using JsonValueMapType = std::unordered_map<std::string, Json::Value>; static bool cmakeCheckStampFile(const std::string& stampName); static bool cmakeCheckStampList(const std::string& stampList); +#ifndef CMAKE_BOOTSTRAP static void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/, void* ctx, const char* /*unused*/, const cmMakefile* /*unused*/) @@ -141,6 +146,7 @@ static void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/, cmake* cm = reinterpret_cast<cmake*>(ctx); cm->MarkCliAsUsed(variable); } +#endif cmake::cmake(Role role, cmState::Mode mode) : FileTimeCache(cm::make_unique<cmFileTimeCache>()) @@ -285,10 +291,11 @@ void cmake::CleanupCommandsAndMacros() // Parse the args bool cmake::SetCacheArgs(const std::vector<std::string>& args) { - bool findPackageMode = false; + auto findPackageMode = false; + auto seenScriptOption = false; for (unsigned int i = 1; i < args.size(); ++i) { std::string const& arg = args[i]; - if (arg.find("-D", 0) == 0) { + if (cmHasLiteralPrefix(arg, "-D")) { std::string entry = arg.substr(2); if (entry.empty()) { ++i; @@ -309,8 +316,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) bool haveValue = false; std::string cachedValue; if (this->WarnUnusedCli) { - if (const std::string* v = - this->State->GetInitializedCacheValue(var)) { + if (cmProp v = this->State->GetInitializedCacheValue(var)) { haveValue = true; cachedValue = *v; } @@ -377,7 +383,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) // -Wno-error=<name> this->DiagLevels[name] = std::min(this->DiagLevels[name], DIAG_WARN); } - } else if (arg.find("-U", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "-U")) { std::string entryPattern = arg.substr(2); if (entryPattern.empty()) { ++i; @@ -407,7 +413,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) for (std::string const& currentEntry : entriesToDelete) { this->State->RemoveCacheEntry(currentEntry); } - } else if (arg.find("-C", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "-C")) { std::string path = arg.substr(2); if (path.empty()) { ++i; @@ -422,7 +428,7 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) // Resolve script path specified on command line relative to $PWD. path = cmSystemTools::CollapseFullPath(path); this->ReadListFile(args, path); - } else if (arg.find("-P", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "-P")) { i++; if (i >= args.size()) { cmSystemTools::Error("-P must be followed by a file name."); @@ -441,7 +447,12 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) this->SetHomeOutputDirectory( cmSystemTools::GetCurrentWorkingDirectory()); this->ReadListFile(args, path); - } else if (arg.find("--find-package", 0) == 0) { + seenScriptOption = true; + } else if (arg == "--" && seenScriptOption) { + // Stop processing CMake args and avoid possible errors + // when arbitrary args are given to CMake script. + break; + } else if (cmHasLiteralPrefix(arg, "--find-package")) { findPackageMode = true; } } @@ -520,11 +531,11 @@ bool cmake::FindPackage(const std::vector<std::string>& args) if (!quiet) { printf("%s not found.\n", packageName.c_str()); } - } else if (mode == "EXIST") { + } else if (mode == "EXIST"_s) { if (!quiet) { printf("%s found.\n", packageName.c_str()); } - } else if (mode == "COMPILE") { + } else if (mode == "COMPILE"_s) { std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS"); std::vector<std::string> includeDirs = cmExpandedList(includes); @@ -535,7 +546,7 @@ bool cmake::FindPackage(const std::vector<std::string>& args) std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS"); printf("%s %s\n", includeFlags.c_str(), definitions.c_str()); - } else if (mode == "LINK") { + } else if (mode == "LINK"_s) { const char* targetName = "dummy"; std::vector<std::string> srcs; cmTarget* tgt = mf->AddExecutable(targetName, srcs, true); @@ -613,9 +624,13 @@ void cmake::SetArgs(const std::vector<std::string>& args) { bool haveToolset = false; bool havePlatform = false; +#if !defined(CMAKE_BOOTSTRAP) + std::string profilingFormat; + std::string profilingOutput; +#endif for (unsigned int i = 1; i < args.size(); ++i) { std::string const& arg = args[i]; - if (arg.find("-H", 0) == 0 || arg.find("-S", 0) == 0) { + if (cmHasLiteralPrefix(arg, "-H") || cmHasLiteralPrefix(arg, "-S")) { std::string path = arg.substr(2); if (path.empty()) { ++i; @@ -633,9 +648,11 @@ void cmake::SetArgs(const std::vector<std::string>& args) path = cmSystemTools::CollapseFullPath(path); cmSystemTools::ConvertToUnixSlashes(path); this->SetHomeDirectory(path); - } else if (arg.find("-O", 0) == 0) { + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) + } else if (cmHasLiteralPrefix(arg, "-O")) { // There is no local generate anymore. Ignore -O option. - } else if (arg.find("-B", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "-B")) { std::string path = arg.substr(2); if (path.empty()) { ++i; @@ -654,54 +671,43 @@ void cmake::SetArgs(const std::vector<std::string>& args) cmSystemTools::ConvertToUnixSlashes(path); this->SetHomeOutputDirectory(path); } else if ((i < args.size() - 2) && - (arg.find("--check-build-system", 0) == 0)) { + cmHasLiteralPrefix(arg, "--check-build-system")) { this->CheckBuildSystemArgument = args[++i]; this->ClearBuildSystem = (atoi(args[++i].c_str()) > 0); } else if ((i < args.size() - 1) && - (arg.find("--check-stamp-file", 0) == 0)) { + cmHasLiteralPrefix(arg, "--check-stamp-file")) { this->CheckStampFile = args[++i]; } else if ((i < args.size() - 1) && - (arg.find("--check-stamp-list", 0) == 0)) { + cmHasLiteralPrefix(arg, "--check-stamp-list")) { this->CheckStampList = args[++i]; - } else if (arg == "--regenerate-during-build") { + } else if (arg == "--regenerate-during-build"_s) { this->RegenerateDuringBuild = true; } #if defined(CMAKE_HAVE_VS_GENERATORS) else if ((i < args.size() - 1) && - (arg.find("--vs-solution-file", 0) == 0)) { + cmHasLiteralPrefix(arg, "--vs-solution-file")) { this->VSSolutionFile = args[++i]; } #endif - else if (arg.find("-D", 0) == 0) { - // skip for now - // in case '-D var=val' is given, also skip the next - // in case '-Dvar=val' is given, don't skip the next - if (arg.size() == 2) { - ++i; - } - } else if (arg.find("-U", 0) == 0) { - // skip for now - // in case '-U var' is given, also skip the next - // in case '-Uvar' is given, don't skip the next - if (arg.size() == 2) { - ++i; - } - } else if (arg.find("-C", 0) == 0) { + else if (cmHasLiteralPrefix(arg, "-D") || cmHasLiteralPrefix(arg, "-U") || + cmHasLiteralPrefix(arg, "-C")) { // skip for now - // in case '-C path' is given, also skip the next - // in case '-Cpath' is given, don't skip the next + // in case '-[DUC] argval' var' is given, also skip the next + // in case '-[DUC]argval' is given, don't skip the next if (arg.size() == 2) { ++i; } - } else if (arg.find("-P", 0) == 0) { + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) + } else if (cmHasLiteralPrefix(arg, "-P")) { // skip for now i++; - } else if (arg.find("--find-package", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--find-package")) { // skip for now i++; - } else if (arg.find("-W", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "-W")) { // skip for now - } else if (arg.find("--graphviz=", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--graphviz=")) { std::string path = arg.substr(strlen("--graphviz=")); path = cmSystemTools::CollapseFullPath(path); cmSystemTools::ConvertToUnixSlashes(path); @@ -710,13 +716,13 @@ void cmake::SetArgs(const std::vector<std::string>& args) cmSystemTools::Error("No file specified for --graphviz"); return; } - } else if (arg.find("--debug-trycompile", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--debug-trycompile")) { std::cout << "debug trycompile on\n"; this->DebugTryCompileOn(); - } else if (arg.find("--debug-output", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--debug-output")) { std::cout << "Running with debug output on.\n"; this->SetDebugOutputOn(true); - } else if (arg.find("--log-level=", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--log-level=")) { const auto logLevel = StringToLogLevel(arg.substr(sizeof("--log-level=") - 1)); if (logLevel == LogLevel::LOG_UNDEFINED) { @@ -725,7 +731,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) } this->SetLogLevel(logLevel); this->LogLevelWasSetViaCLI = true; - } else if (arg.find("--loglevel=", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--loglevel=")) { // This is supported for backward compatibility. This option only // appeared in the 3.15.x release series and was renamed to // --log-level in 3.16.0 @@ -737,16 +743,16 @@ void cmake::SetArgs(const std::vector<std::string>& args) } this->SetLogLevel(logLevel); this->LogLevelWasSetViaCLI = true; - } else if (arg == "--log-context") { + } else if (arg == "--log-context"_s) { this->SetShowLogContext(true); - } else if (arg.find("--debug-find", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--debug-find")) { std::cout << "Running with debug output on for the `find` commands.\n"; this->SetDebugFindOutputOn(true); - } else if (arg.find("--trace-expand", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--trace-expand")) { std::cout << "Running with expanded trace output on.\n"; this->SetTrace(true); this->SetTraceExpand(true); - } else if (arg.find("--trace-format=", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--trace-format=")) { this->SetTrace(true); const auto traceFormat = StringToTraceFormat(arg.substr(strlen("--trace-format="))); @@ -756,35 +762,35 @@ void cmake::SetArgs(const std::vector<std::string>& args) return; } this->SetTraceFormat(traceFormat); - } else if (arg.find("--trace-source=", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--trace-source=")) { std::string file = arg.substr(strlen("--trace-source=")); cmSystemTools::ConvertToUnixSlashes(file); this->AddTraceSource(file); this->SetTrace(true); - } else if (arg.find("--trace-redirect=", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--trace-redirect=")) { std::string file = arg.substr(strlen("--trace-redirect=")); cmSystemTools::ConvertToUnixSlashes(file); this->SetTraceFile(file); this->SetTrace(true); - } else if (arg.find("--trace", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--trace")) { std::cout << "Running with trace output on.\n"; this->SetTrace(true); this->SetTraceExpand(false); - } else if (arg.find("--warn-uninitialized", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--warn-uninitialized")) { std::cout << "Warn about uninitialized values.\n"; this->SetWarnUninitialized(true); - } else if (arg.find("--warn-unused-vars", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--warn-unused-vars")) { std::cout << "Finding unused variables.\n"; this->SetWarnUnused(true); - } else if (arg.find("--no-warn-unused-cli", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--no-warn-unused-cli")) { std::cout << "Not searching for unused variables given on the " << "command line.\n"; this->SetWarnUnusedCli(false); - } else if (arg.find("--check-system-vars", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "--check-system-vars")) { std::cout << "Also check system files when warning about unused and " << "uninitialized variables.\n"; this->SetCheckSystemVars(true); - } else if (arg.find("-A", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "-A")) { std::string value = arg.substr(2); if (value.empty()) { ++i; @@ -800,7 +806,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) } this->SetGeneratorPlatform(value); havePlatform = true; - } else if (arg.find("-T", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "-T")) { std::string value = arg.substr(2); if (value.empty()) { ++i; @@ -816,7 +822,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) } this->SetGeneratorToolset(value); haveToolset = true; - } else if (arg.find("-G", 0) == 0) { + } else if (cmHasLiteralPrefix(arg, "-G")) { std::string value = arg.substr(2); if (value.empty()) { ++i; @@ -840,6 +846,20 @@ void cmake::SetArgs(const std::vector<std::string>& args) return; } this->SetGlobalGenerator(std::move(gen)); +#if !defined(CMAKE_BOOTSTRAP) + } else if (cmHasLiteralPrefix(arg, "--profiling-format")) { + profilingFormat = arg.substr(strlen("--profiling-format=")); + if (profilingFormat.empty()) { + cmSystemTools::Error("No format specified for --profiling-format"); + } + } else if (cmHasLiteralPrefix(arg, "--profiling-output")) { + profilingOutput = arg.substr(strlen("--profiling-output=")); + profilingOutput = cmSystemTools::CollapseFullPath(profilingOutput); + cmSystemTools::ConvertToUnixSlashes(profilingOutput); + if (profilingOutput.empty()) { + cmSystemTools::Error("No path specified for --profiling-output"); + } +#endif } // no option assume it is the path to the source or an existing build else { @@ -857,6 +877,29 @@ void cmake::SetArgs(const std::vector<std::string>& args) } } +#if !defined(CMAKE_BOOTSTRAP) + if (!profilingOutput.empty() || !profilingFormat.empty()) { + if (profilingOutput.empty()) { + cmSystemTools::Error( + "--profiling-format specified but no --profiling-output!"); + return; + } + if (profilingFormat == "google-trace"_s) { + try { + this->ProfilingOutput = + cm::make_unique<cmMakefileProfilingData>(profilingOutput); + } catch (std::runtime_error& e) { + cmSystemTools::Error( + cmStrCat("Could not start profiling: ", e.what())); + return; + } + } else { + cmSystemTools::Error("Invalid format specified for --profiling-format"); + return; + } + } +#endif + const bool haveSourceDir = !this->GetHomeDirectory().empty(); const bool haveBinaryDir = !this->GetHomeOutputDirectory().empty(); @@ -992,9 +1035,9 @@ void cmake::SetDirectoriesFromFile(const std::string& arg) std::string fullPath = cmSystemTools::CollapseFullPath(arg); std::string name = cmSystemTools::GetFilenameName(fullPath); name = cmSystemTools::LowerCase(name); - if (name == "cmakecache.txt") { + if (name == "cmakecache.txt"_s) { cachePath = cmSystemTools::GetFilenamePath(fullPath); - } else if (name == "cmakelists.txt") { + } else if (name == "cmakelists.txt"_s) { listPath = cmSystemTools::GetFilenamePath(fullPath); } } else { @@ -1003,7 +1046,7 @@ void cmake::SetDirectoriesFromFile(const std::string& arg) std::string fullPath = cmSystemTools::CollapseFullPath(arg); std::string name = cmSystemTools::GetFilenameName(fullPath); name = cmSystemTools::LowerCase(name); - if (name == "cmakecache.txt" || name == "cmakelists.txt") { + if (name == "cmakecache.txt"_s || name == "cmakelists.txt"_s) { argIsFile = true; listPath = cmSystemTools::GetFilenamePath(fullPath); } else { @@ -1014,11 +1057,11 @@ void cmake::SetDirectoriesFromFile(const std::string& arg) // If there is a CMakeCache.txt file, use its settings. if (!cachePath.empty()) { if (this->LoadCache(cachePath)) { - const char* existingValue = + cmProp existingValue = this->State->GetCacheEntryValue("CMAKE_HOME_DIRECTORY"); if (existingValue) { this->SetHomeOutputDirectory(cachePath); - this->SetHomeDirectory(existingValue); + this->SetHomeDirectory(*existingValue); return; } } @@ -1361,12 +1404,12 @@ int cmake::HandleDeleteCacheVariables(const std::string& var) i++; save.value = *i; warning << *i << "\n"; - const char* existingValue = this->State->GetCacheEntryValue(save.key); + cmProp existingValue = this->State->GetCacheEntryValue(save.key); if (existingValue) { save.type = this->State->GetCacheEntryType(save.key); - if (const char* help = + if (cmProp help = this->State->GetCacheEntryProperty(save.key, "HELPSTRING")) { - save.help = help; + save.help = *help; } } saved.push_back(std::move(save)); @@ -1411,9 +1454,9 @@ int cmake::Configure() if (this->DiagLevels.count("dev") == 1) { bool setDeprecatedVariables = false; - const char* cachedWarnDeprecated = + cmProp cachedWarnDeprecated = this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED"); - const char* cachedErrorDeprecated = + cmProp cachedErrorDeprecated = this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED"); // don't overwrite deprecated warning setting from a previous invocation @@ -1452,23 +1495,23 @@ int cmake::Configure() // Cache variables may have already been set by a previous invocation, // so we cannot rely on command line options alone. Always ensure our // messenger is in sync with the cache. - const char* value = this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED"); - this->Messenger->SetSuppressDeprecatedWarnings(value && cmIsOff(value)); + cmProp value = this->State->GetCacheEntryValue("CMAKE_WARN_DEPRECATED"); + this->Messenger->SetSuppressDeprecatedWarnings(value && cmIsOff(*value)); value = this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED"); - this->Messenger->SetDeprecatedWarningsAsErrors(cmIsOn(value)); + this->Messenger->SetDeprecatedWarningsAsErrors(value && cmIsOn(*value)); value = this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_WARNINGS"); - this->Messenger->SetSuppressDevWarnings(cmIsOn(value)); + this->Messenger->SetSuppressDevWarnings(value && cmIsOn(*value)); value = this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_ERRORS"); - this->Messenger->SetDevWarningsAsErrors(value && cmIsOff(value)); + this->Messenger->SetDevWarningsAsErrors(value && cmIsOff(*value)); int ret = this->ActualConfigure(); - const char* delCacheVars = + cmProp delCacheVars = this->State->GetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_"); - if (delCacheVars && delCacheVars[0] != 0) { - return this->HandleDeleteCacheVariables(delCacheVars); + if (delCacheVars && !delCacheVars->empty()) { + return this->HandleDeleteCacheVariables(*delCacheVars); } return ret; } @@ -1493,9 +1536,8 @@ int cmake::ActualConfigure() // no generator specified on the command line if (!this->GlobalGenerator) { - const std::string* genName = - this->State->GetInitializedCacheValue("CMAKE_GENERATOR"); - const std::string* extraGenName = + cmProp genName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR"); + cmProp extraGenName = this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR"); if (genName) { std::string fullName = @@ -1518,8 +1560,7 @@ int cmake::ActualConfigure() } } - const std::string* genName = - this->State->GetInitializedCacheValue("CMAKE_GENERATOR"); + cmProp genName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR"); if (genName) { if (!this->GlobalGenerator->MatchesGeneratorName(*genName)) { std::string message = @@ -1541,7 +1582,7 @@ int cmake::ActualConfigure() cmStateEnums::INTERNAL); } - if (const std::string* instance = + if (cmProp instance = this->State->GetInitializedCacheValue("CMAKE_GENERATOR_INSTANCE")) { if (this->GeneratorInstanceSet && this->GeneratorInstance != *instance) { std::string message = @@ -1558,7 +1599,7 @@ int cmake::ActualConfigure() "Generator instance identifier.", cmStateEnums::INTERNAL); } - if (const std::string* platformName = + if (cmProp platformName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR_PLATFORM")) { if (this->GeneratorPlatformSet && this->GeneratorPlatform != *platformName) { @@ -1576,7 +1617,7 @@ int cmake::ActualConfigure() "Name of generator platform.", cmStateEnums::INTERNAL); } - if (const std::string* tsName = + if (cmProp tsName = this->State->GetInitializedCacheValue("CMAKE_GENERATOR_TOOLSET")) { if (this->GeneratorToolsetSet && this->GeneratorToolset != *tsName) { std::string message = @@ -1891,13 +1932,13 @@ void cmake::AddCacheEntry(const std::string& key, const char* value, cmStateEnums::CacheEntryType(type)); this->UnwatchUnusedCli(key); - if (key == "CMAKE_WARN_DEPRECATED") { + if (key == "CMAKE_WARN_DEPRECATED"_s) { this->Messenger->SetSuppressDeprecatedWarnings(value && cmIsOff(value)); - } else if (key == "CMAKE_ERROR_DEPRECATED") { + } else if (key == "CMAKE_ERROR_DEPRECATED"_s) { this->Messenger->SetDeprecatedWarningsAsErrors(cmIsOn(value)); - } else if (key == "CMAKE_SUPPRESS_DEVELOPER_WARNINGS") { + } else if (key == "CMAKE_SUPPRESS_DEVELOPER_WARNINGS"_s) { this->Messenger->SetSuppressDevWarnings(cmIsOn(value)); - } else if (key == "CMAKE_SUPPRESS_DEVELOPER_ERRORS") { + } else if (key == "CMAKE_SUPPRESS_DEVELOPER_ERRORS"_s) { this->Messenger->SetDevWarningsAsErrors(value && cmIsOff(value)); } } @@ -1933,9 +1974,10 @@ std::string cmake::StripExtension(const std::string& file) const { auto dotpos = file.rfind('.'); if (dotpos != std::string::npos) { - auto ext = file.substr(dotpos + 1); #if defined(_WIN32) || defined(__APPLE__) - ext = cmSystemTools::LowerCase(ext); + auto ext = cmSystemTools::LowerCase(file.substr(dotpos + 1)); +#else + auto ext = cm::string_view(file).substr(dotpos + 1); #endif if (this->IsSourceExtension(ext) || this->IsHeaderExtension(ext)) { return file.substr(0, dotpos); @@ -1946,7 +1988,7 @@ std::string cmake::StripExtension(const std::string& file) const const char* cmake::GetCacheDefinition(const std::string& name) const { - const std::string* p = this->State->GetInitializedCacheValue(name); + cmProp p = this->State->GetInitializedCacheValue(name); return p ? p->c_str() : nullptr; } @@ -2153,7 +2195,7 @@ void cmake::PrintGeneratorList() void cmake::UpdateConversionPathTable() { // Update the path conversion table with any specified file: - const std::string* tablepath = + cmProp tablepath = this->State->GetInitializedCacheValue("CMAKE_PATH_TRANSLATION_FILE"); if (tablepath) { @@ -2244,9 +2286,7 @@ int cmake::CheckBuildSystem() // If any byproduct of makefile generation is missing we must re-run. std::vector<std::string> products; - if (const char* productStr = mf.GetDefinition("CMAKE_MAKEFILE_PRODUCTS")) { - cmExpandList(productStr, products); - } + mf.GetDefExpandList("CMAKE_MAKEFILE_PRODUCTS", products); for (std::string const& p : products) { if (!(cmSystemTools::FileExists(p) || cmSystemTools::FileIsSymlink(p))) { if (verbose) { @@ -2261,11 +2301,8 @@ int cmake::CheckBuildSystem() // Get the set of dependencies and outputs. std::vector<std::string> depends; std::vector<std::string> outputs; - const char* dependsStr = mf.GetDefinition("CMAKE_MAKEFILE_DEPENDS"); - const char* outputsStr = mf.GetDefinition("CMAKE_MAKEFILE_OUTPUTS"); - if (dependsStr && outputsStr) { - cmExpandList(dependsStr, depends); - cmExpandList(outputsStr, outputs); + if (mf.GetDefExpandList("CMAKE_MAKEFILE_DEPENDS", depends)) { + mf.GetDefExpandList("CMAKE_MAKEFILE_OUTPUTS", outputs); } if (depends.empty() || outputs.empty()) { // Not enough information was provided to do the test. Just rerun. @@ -2383,7 +2420,7 @@ void cmake::AppendProperty(const std::string& prop, const std::string& value, this->State->AppendGlobalProperty(prop, value, asString); } -const char* cmake::GetProperty(const std::string& prop) +cmProp cmake::GetProperty(const std::string& prop) { return this->State->GetGlobalProperty(prop); } @@ -2435,7 +2472,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) bool writeToStdout = true; for (unsigned int i = 1; i < args.size(); ++i) { std::string const& arg = args[i]; - if (arg.find("-G", 0) == 0) { + if (cmHasLiteralPrefix(arg, "-G")) { std::string value = arg.substr(2); if (value.empty()) { ++i; @@ -2624,10 +2661,10 @@ void cmake::IssueMessage(MessageType t, std::string const& text, std::vector<std::string> cmake::GetDebugConfigs() { std::vector<std::string> configs; - if (const char* config_list = + if (cmProp config_list = this->State->GetGlobalProperty("DEBUG_CONFIGURATIONS")) { // Expand the specified list and convert to upper-case. - cmExpandList(config_list, configs); + cmExpandList(*config_list, configs); std::transform(configs.begin(), configs.end(), configs.begin(), cmSystemTools::UpperCase); } @@ -2657,59 +2694,58 @@ int cmake::Build(int jobs, const std::string& dir, std::cerr << "Error: could not load cache\n"; return 1; } - const char* cachedGenerator = - this->State->GetCacheEntryValue("CMAKE_GENERATOR"); + cmProp cachedGenerator = this->State->GetCacheEntryValue("CMAKE_GENERATOR"); if (!cachedGenerator) { std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n"; return 1; } - auto gen = this->CreateGlobalGenerator(cachedGenerator); + auto gen = this->CreateGlobalGenerator(*cachedGenerator); if (!gen) { - std::cerr << "Error: could create CMAKE_GENERATOR \"" << cachedGenerator + std::cerr << "Error: could create CMAKE_GENERATOR \"" << *cachedGenerator << "\"\n"; return 1; } this->SetGlobalGenerator(std::move(gen)); - const char* cachedGeneratorInstance = + cmProp cachedGeneratorInstance = this->State->GetCacheEntryValue("CMAKE_GENERATOR_INSTANCE"); if (cachedGeneratorInstance) { cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot()); - if (!this->GlobalGenerator->SetGeneratorInstance(cachedGeneratorInstance, + if (!this->GlobalGenerator->SetGeneratorInstance(*cachedGeneratorInstance, &mf)) { return 1; } } - const char* cachedGeneratorPlatform = + cmProp cachedGeneratorPlatform = this->State->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM"); if (cachedGeneratorPlatform) { cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot()); - if (!this->GlobalGenerator->SetGeneratorPlatform(cachedGeneratorPlatform, + if (!this->GlobalGenerator->SetGeneratorPlatform(*cachedGeneratorPlatform, &mf)) { return 1; } } - const char* cachedGeneratorToolset = + cmProp cachedGeneratorToolset = this->State->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET"); if (cachedGeneratorToolset) { cmMakefile mf(this->GetGlobalGenerator(), this->GetCurrentSnapshot()); - if (!this->GlobalGenerator->SetGeneratorToolset(cachedGeneratorToolset, + if (!this->GlobalGenerator->SetGeneratorToolset(*cachedGeneratorToolset, true, &mf)) { return 1; } } std::string output; std::string projName; - const char* cachedProjectName = + cmProp cachedProjectName = this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME"); if (!cachedProjectName) { std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n"; return 1; } - projName = cachedProjectName; + projName = *cachedProjectName; - const char* cachedVerbose = + cmProp cachedVerbose = this->State->GetCacheEntryValue("CMAKE_VERBOSE_MAKEFILE"); - if (cmIsOn(cachedVerbose)) { + if (cachedVerbose && cmIsOn(*cachedVerbose)) { verbose = true; } @@ -2793,16 +2829,16 @@ bool cmake::Open(const std::string& dir, bool dryRun) std::cerr << "Error: could not load cache\n"; return false; } - const char* genName = this->State->GetCacheEntryValue("CMAKE_GENERATOR"); + cmProp genName = this->State->GetCacheEntryValue("CMAKE_GENERATOR"); if (!genName) { std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n"; return false; } - const std::string* extraGenName = + cmProp extraGenName = this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR"); std::string fullName = cmExternalMakefileProjectGenerator::CreateFullGeneratorName( - genName, extraGenName ? *extraGenName : ""); + *genName, extraGenName ? *extraGenName : ""); std::unique_ptr<cmGlobalGenerator> gen = this->CreateGlobalGenerator(fullName); @@ -2812,21 +2848,21 @@ bool cmake::Open(const std::string& dir, bool dryRun) return false; } - const char* cachedProjectName = + cmProp cachedProjectName = this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME"); if (!cachedProjectName) { std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n"; return false; } - return gen->Open(dir, cachedProjectName, dryRun); + return gen->Open(dir, *cachedProjectName, dryRun); } void cmake::WatchUnusedCli(const std::string& var) { #ifndef CMAKE_BOOTSTRAP this->VariableWatch->AddWatch(var, cmWarnUnusedCliWarning, this); - if (!cmContains(this->UsedCliVariables, var)) { + if (!cm::contains(this->UsedCliVariables, var)) { this->UsedCliVariables[var] = false; } #endif @@ -2953,3 +2989,15 @@ void cmake::SetDeprecatedWarningsAsErrors(bool b) " and functions.", cmStateEnums::INTERNAL); } + +#if !defined(CMAKE_BOOTSTRAP) +cmMakefileProfilingData& cmake::GetProfilingOutput() +{ + return *(this->ProfilingOutput); +} + +bool cmake::IsProfilingEnabled() const +{ + return static_cast<bool>(this->ProfilingOutput); +} +#endif diff --git a/Source/cmake.h b/Source/cmake.h index 35425ec52..086ec8765 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -16,16 +16,19 @@ #include <utility> #include <vector> +#include <cm/string_view> + #include "cmGeneratedFileStream.h" #include "cmInstalledFile.h" #include "cmListFileCache.h" #include "cmMessageType.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" #if !defined(CMAKE_BOOTSTRAP) -# include "cm_jsoncpp_value.h" +# include <cm3p/json/value.h> #endif class cmExternalMakefileProjectGeneratorFactory; @@ -34,6 +37,9 @@ class cmFileTimeCache; class cmGlobalGenerator; class cmGlobalGeneratorFactory; class cmMakefile; +#if !defined(CMAKE_BOOTSTRAP) +class cmMakefileProfilingData; +#endif class cmMessenger; class cmVariableWatch; struct cmDocumentationEntry; @@ -135,13 +141,13 @@ public: struct FileExtensions { - bool Test(std::string const& ext) const + bool Test(cm::string_view ext) const { return (this->unordered.find(ext) != this->unordered.end()); } std::vector<std::string> ordered; - std::unordered_set<std::string> unordered; + std::unordered_set<cm::string_view> unordered; }; using InstalledFilesMap = std::map<std::string, cmInstalledFile>; @@ -263,7 +269,7 @@ public: return this->SourceFileExtensions.ordered; } - bool IsSourceExtension(const std::string& ext) const + bool IsSourceExtension(cm::string_view ext) const { return this->SourceFileExtensions.Test(ext); } @@ -273,7 +279,7 @@ public: return this->HeaderFileExtensions.ordered; } - bool IsHeaderExtension(const std::string& ext) const + bool IsHeaderExtension(cm::string_view ext) const { return this->HeaderFileExtensions.Test(ext); } @@ -283,7 +289,7 @@ public: return this->CudaFileExtensions.ordered; } - bool IsCudaExtension(const std::string& ext) const + bool IsCudaExtension(cm::string_view ext) const { return this->CudaFileExtensions.Test(ext); } @@ -293,7 +299,7 @@ public: return this->FortranFileExtensions.ordered; } - bool IsFortranExtension(const std::string& ext) const + bool IsFortranExtension(cm::string_view ext) const { return this->FortranFileExtensions.Test(ext); } @@ -361,7 +367,7 @@ public: void SetProperty(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); + cmProp GetProperty(const std::string& prop); bool GetPropertyAsBool(const std::string& prop); //! Get or create an cmInstalledFile instance and return a pointer to it @@ -549,6 +555,11 @@ public: bool GetRegenerateDuringBuild() const { return this->RegenerateDuringBuild; } +#if !defined(CMAKE_BOOTSTRAP) + cmMakefileProfilingData& GetProfilingOutput(); + bool IsProfilingEnabled() const; +#endif + protected: void RunCheckForUnusedVariables(); int HandleDeleteCacheVariables(const std::string& var); @@ -657,6 +668,10 @@ private: void AppendGlobalGeneratorsDocumentation(std::vector<cmDocumentationEntry>&); void AppendExtraGeneratorsDocumentation(std::vector<cmDocumentationEntry>&); + +#if !defined(CMAKE_BOOTSTRAP) + std::unique_ptr<cmMakefileProfilingData> ProfilingOutput; +#endif }; #define CMAKE_STANDARD_OPTIONS_TABLE \ diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 494d5d982..d662a9abc 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -1,6 +1,8 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmConfigure.h" // IWYU pragma: keep + #include <cassert> #include <cctype> #include <climits> @@ -11,9 +13,12 @@ #include <cmext/algorithm> +#include <cm3p/uv.h> + #include "cmDocumentationEntry.h" // IWYU pragma: keep #include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -27,8 +32,6 @@ #endif #include "cmsys/Encoding.hxx" - -#include "cm_uv.h" #if defined(_WIN32) && !defined(CMAKE_BOOTSTRAP) # include "cmsys/ConsoleBuf.hxx" #endif @@ -93,6 +96,14 @@ const char* cmDocumentationOptions[][2] = { { "--check-system-vars", "Find problems with variable usage in system " "files." }, +# if !defined(CMAKE_BOOTSTRAP) + { "--profiling-format=<fmt>", + "Output data for profiling CMake scripts. Supported formats: " + "google-trace" }, + { "--profiling-output=<file>", + "Select an output path for the profiling data enabled through " + "--profiling-format." }, +# endif { nullptr, nullptr } }; @@ -286,16 +297,16 @@ int do_cmake(int ac, char const* const* av) cmStateEnums::CacheEntryType t = cm.GetState()->GetCacheEntryType(k); if (t != cmStateEnums::INTERNAL && t != cmStateEnums::STATIC && t != cmStateEnums::UNINITIALIZED) { - const char* advancedProp = + cmProp advancedProp = cm.GetState()->GetCacheEntryProperty(k, "ADVANCED"); if (list_all_cached || !advancedProp) { if (list_help) { - std::cout << "// " - << cm.GetState()->GetCacheEntryProperty(k, "HELPSTRING") - << std::endl; + cmProp help = + cm.GetState()->GetCacheEntryProperty(k, "HELPSTRING"); + std::cout << "// " << (help ? *help : "") << std::endl; } std::cout << k << ":" << cmState::CacheEntryTypeToString(t) << "=" - << cm.GetState()->GetCacheEntryValue(k) << std::endl; + << cm.GetState()->GetSafeCacheEntryValue(k) << std::endl; if (list_help) { std::cout << std::endl; } @@ -312,6 +323,7 @@ int do_cmake(int ac, char const* const* av) return 0; } +#ifndef CMAKE_BOOTSTRAP int extract_job_number(int& index, char const* current, char const* next, int len_of_flag) { @@ -341,6 +353,7 @@ int extract_job_number(int& index, char const* current, char const* next, } return jobs; } +#endif int do_build(int ac, char const* const* av) { @@ -706,6 +719,8 @@ int main(int ac, char const* const* av) #ifndef CMAKE_BOOTSTRAP cmDynamicLoader::FlushCache(); #endif - uv_loop_close(uv_default_loop()); + if (uv_loop_t* loop = uv_default_loop()) { + uv_loop_close(loop); + } return ret; } diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx index caf645301..5c27ac103 100644 --- a/Source/cmcldeps.cxx +++ b/Source/cmcldeps.cxx @@ -25,6 +25,7 @@ #include "cmsys/Encoding.hxx" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" // We don't want any wildcard expansion. @@ -63,7 +64,7 @@ static void usage(const char* msg) msg); } -static std::string trimLeadingSpace(const std::string& cmdline) +static cm::string_view trimLeadingSpace(cm::string_view cmdline) { int i = 0; for (; cmdline[i] == ' '; ++i) @@ -81,34 +82,30 @@ static void replaceAll(std::string& str, const std::string& search, } } -bool startsWith(const std::string& str, const std::string& what) -{ - return str.compare(0, what.size(), what) == 0; -} - // Strips one argument from the cmdline and returns it. "surrounding quotes" // are removed from the argument if there were any. static std::string getArg(std::string& cmdline) { - std::string ret; bool in_quoted = false; unsigned int i = 0; - cmdline = trimLeadingSpace(cmdline); + cm::string_view cmdview = trimLeadingSpace(cmdline); + size_t spaceCnt = cmdline.size() - cmdview.size(); for (;; ++i) { - if (i >= cmdline.size()) + if (i >= cmdview.size()) usage("Couldn't parse arguments."); - if (!in_quoted && cmdline[i] == ' ') + if (!in_quoted && cmdview[i] == ' ') break; // "a b" "x y" - if (cmdline[i] == '"') + if (cmdview[i] == '"') in_quoted = !in_quoted; } - ret = cmdline.substr(0, i); - if (ret[0] == '"' && ret[i - 1] == '"') - ret = ret.substr(1, ret.size() - 2); - cmdline = cmdline.substr(i); + cmdview = cmdview.substr(0, i); + if (cmdview[0] == '"' && cmdview[i - 1] == '"') + cmdview = cmdview.substr(1, i - 2); + std::string ret(cmdview); + cmdline.erase(0, spaceCnt + i); return ret; } @@ -127,7 +124,7 @@ static void parseCommandLine(LPWSTR wincmdline, std::string& lang, prefix = getArg(cmdline); clpath = getArg(cmdline); binpath = getArg(cmdline); - rest = trimLeadingSpace(cmdline); + rest = std::string(trimLeadingSpace(cmdline)); } // Not all backslashes need to be escaped in a depfile, but it's easier that @@ -169,8 +166,8 @@ static void outputDepFile(const std::string& dfile, const std::string& objfile, // build.ninja file. Therefore we need to canonicalize the path to use // backward slashes and relativize the path to the build directory. replaceAll(tmp, "/", "\\"); - if (startsWith(tmp, cwd)) - tmp = tmp.substr(cwd.size()); + if (cmHasPrefix(tmp, cwd)) + tmp.erase(0, cwd.size()); escapePath(tmp); fprintf(out, "%s \\\n", tmp.c_str()); } @@ -194,7 +191,7 @@ std::string replace(const std::string& str, const std::string& what, return replaced.replace(pos, what.size(), replacement); } -static int process(const std::string& srcfilename, const std::string& dfile, +static int process(cm::string_view srcfilename, const std::string& dfile, const std::string& objfile, const std::string& prefix, const std::string& cmd, const std::string& dir = "", bool quiet = false) @@ -221,13 +218,14 @@ static int process(const std::string& srcfilename, const std::string& dfile, std::vector<std::string> includes; bool isFirstLine = true; // cl prints always first the source filename while (std::getline(ss, line)) { - if (startsWith(line, prefix)) { - std::string inc = trimLeadingSpace(line.substr(prefix.size()).c_str()); + cm::string_view inc(line); + if (cmHasPrefix(inc, prefix)) { + inc = trimLeadingSpace(inc.substr(prefix.size())); if (inc.back() == '\r') // blech, stupid \r\n inc = inc.substr(0, inc.size() - 1); - includes.push_back(inc); + includes.emplace_back(std::string(inc)); } else { - if (!isFirstLine || !startsWith(line, srcfilename)) { + if (!isFirstLine || !cmHasPrefix(inc, srcfilename)) { if (!quiet || exit_code != 0) { fprintf(stdout, "%s\n", line.c_str()); } @@ -258,14 +256,10 @@ int main() cl, binpath, rest); // needed to suppress filename output of msvc tools - std::string srcfilename; - { - std::string::size_type pos = srcfile.rfind('\\'); - if (pos == std::string::npos) { - srcfilename = srcfile; - } else { - srcfilename = srcfile.substr(pos + 1); - } + cm::string_view srcfilename(srcfile); + std::string::size_type pos = srcfile.rfind('\\'); + if (pos != std::string::npos) { + srcfilename = srcfilename.substr(pos + 1); } std::string nol = " /nologo "; @@ -286,7 +280,7 @@ int main() // call cl in object dir so the .i is generated there std::string objdir; { - std::string::size_type pos = objfile.rfind("\\"); + pos = objfile.rfind("\\"); if (pos != std::string::npos) { objdir = objfile.substr(0, pos); } diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 2b8ea24fb..de76d734e 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -4,11 +4,9 @@ #include <cmext/algorithm> +#include <cm3p/uv.h> #include <fcntl.h> -#include "cm_uv.h" - -#include "cmAlgorithms.h" #include "cmDuration.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" @@ -90,6 +88,7 @@ void CMakeCommandUsage(const char* program) << "Available commands: \n" << " capabilities - Report capabilities built into cmake " "in JSON format\n" + << " cat <files>... - concat the files and print them to the standard output\n" << " chdir dir cmd [args...] - run command in a given directory\n" << " compare_files [--ignore-eol] file1 file2\n" << " - check if file1 is same as file2\n" @@ -180,6 +179,13 @@ static bool cmTarFilesFrom(std::string const& file, return true; } +static void cmCatFile(const std::string& fileToAppend) +{ + cmsys::ifstream source(fileToAppend.c_str(), + (std::ios::binary | std::ios::in)); + std::cout << source.rdbuf(); +} + static bool cmRemoveDirectory(const std::string& dir, bool recursive = true) { if (cmSystemTools::FileIsSymlink(dir)) { @@ -678,7 +684,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) } else if (!a.empty() && a[0] == '-') { // Environment variable and command names cannot start in '-', // so this must be an unknown option. - std::cerr << "cmake -E env: unknown option '" << a << "'" + std::cerr << "cmake -E env: unknown option '" << a << '\'' << std::endl; return 1; } else if (a.find('=') != std::string::npos) { @@ -927,6 +933,33 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) return HashSumFile(args, cmCryptoHash::AlgoSHA512); } + // Command to concat files into one + if (args[1] == "cat" && args.size() >= 3) { + int return_value = 0; + for (auto const& arg : cmMakeRange(args).advance(2)) { + if (cmHasLiteralPrefix(arg, "-")) { + if (arg != "--") { + cmSystemTools::Error(arg + ": option not handled"); + return_value = 1; + } + } else if (!cmSystemTools::TestFileAccess(arg, + cmsys::TEST_FILE_READ) && + cmSystemTools::TestFileAccess(arg, cmsys::TEST_FILE_OK)) { + cmSystemTools::Error(arg + ": permission denied (ignoring)"); + return_value = 1; + } else if (cmSystemTools::FileIsDirectory(arg)) { + cmSystemTools::Error(arg + ": is a directory (ignoring)"); + return_value = 1; + } else if (!cmSystemTools::FileExists(arg)) { + cmSystemTools::Error(arg + ": no such file or directory (ignoring)"); + return_value = 1; + } else { + cmCatFile(arg); + } + } + return return_value; + } + // Command to change directory and run a program. if (args[1] == "chdir" && args.size() >= 4) { std::string const& directory = args[2]; @@ -1054,8 +1087,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) homeOutDir = args[5]; startOutDir = args[6]; depInfo = args[7]; - if (args.size() >= 9 && args[8].length() >= 8 && - args[8].substr(0, 8) == "--color=") { + if (args.size() >= 9 && cmHasLiteralPrefix(args[8], "--color=")) { // Enable or disable color based on the switch value. color = (args[8].size() == 8 || cmIsOn(args[8].substr(8))); } @@ -1186,7 +1218,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) } } else if (cmHasLiteralPrefix(arg, "--format=")) { format = arg.substr(9); - if (!cmContains(knownFormats, format)) { + if (!cm::contains(knownFormats, format)) { cmSystemTools::Error("Unknown -E tar --format= argument: " + format); return 1; @@ -1304,7 +1336,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) } else if (arg == "--debug") { pipe.clear(); isDebug = true; - } else if (arg.substr(0, pipePrefix.size()) == pipePrefix) { + } else if (cmHasPrefix(arg, pipePrefix)) { isDebug = false; pipe = arg.substr(pipePrefix.size()); if (pipe.empty()) { @@ -1511,7 +1543,7 @@ int cmcmd::ExecuteEchoColor(std::vector<std::string> const& args) bool newline = true; std::string progressDir; for (auto const& arg : cmMakeRange(args).advance(2)) { - if (arg.find("--switch=") == 0) { + if (cmHasLiteralPrefix(arg, "--switch=")) { // Enable or disable color based on the switch value. std::string value = arg.substr(9); if (!value.empty()) { @@ -1566,7 +1598,7 @@ int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args) // args[3] == --verbose=? bool verbose = false; if (args.size() >= 4) { - if (args[3].find("--verbose=") == 0) { + if (cmHasLiteralPrefix(args[3], "--verbose=")) { if (!cmIsOff(args[3].substr(10))) { verbose = true; } @@ -1654,11 +1686,13 @@ int cmcmd::WindowsCEEnvironment(const char* version, const std::string& name) cmVisualStudioWCEPlatformParser parser(name.c_str()); parser.ParseVersion(version); if (parser.Found()) { - std::cout << "@echo off" << std::endl; - std::cout << "echo Environment Selection: " << name << std::endl; - std::cout << "set PATH=" << parser.GetPathDirectories() << std::endl; - std::cout << "set INCLUDE=" << parser.GetIncludeDirectories() << std::endl; - std::cout << "set LIB=" << parser.GetLibraryDirectories() << std::endl; + /* clang-format off */ + std::cout << "@echo off\n" + "echo Environment Selection: " << name << "\n" + "set PATH=" << parser.GetPathDirectories() << "\n" + "set INCLUDE=" << parser.GetIncludeDirectories() << "\n" + "set LIB=" << parser.GetLibraryDirectories() << std::endl; + /* clang-format on */ return 0; } #else @@ -1845,7 +1879,7 @@ int cmcmd::VisualStudioLink(std::vector<std::string> const& args, int type) std::vector<std::string> expandedArgs; for (std::string const& i : args) { // check for nmake temporary files - if (i[0] == '@' && i.find("@CMakeFiles") != 0) { + if (i[0] == '@' && !cmHasLiteralPrefix(i, "@CMakeFiles")) { cmsys::ifstream fin(i.substr(1).c_str()); std::string line; while (cmSystemTools::GetLineFromStream(fin, line)) { @@ -1971,9 +2005,8 @@ bool cmVSLink::Parse(std::vector<std::string>::const_iterator argBeg, // Parse the link command to extract information we need. for (; arg != argEnd; ++arg) { - if (cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL:YES") == 0) { - this->Incremental = true; - } else if (cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL") == 0) { + if (cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL:YES") == 0 || + cmSystemTools::Strucmp(arg->c_str(), "/INCREMENTAL") == 0) { this->Incremental = true; } else if (cmSystemTools::Strucmp(arg->c_str(), "/MANIFEST:NO") == 0) { this->LinkGeneratesManifest = false; @@ -2083,12 +2116,18 @@ int cmVSLink::LinkIncremental() } // If we have not previously generated a manifest file, - // generate an empty one so the resource compiler succeeds. + // generate a manifest file so the resource compiler succeeds. if (!cmSystemTools::FileExists(this->ManifestFile)) { if (this->Verbose) { std::cout << "Create empty: " << this->ManifestFile << "\n"; } - cmsys::ofstream foutTmp(this->ManifestFile.c_str()); + if (this->UserManifests.empty()) { + // generate an empty manifest because there are no user provided + // manifest files. + cmsys::ofstream foutTmp(this->ManifestFile.c_str()); + } else { + this->RunMT("/out:" + this->ManifestFile, false); + } } // Compile the resource file. @@ -2156,7 +2195,10 @@ int cmVSLink::RunMT(std::string const& out, bool notify) mtCommand.push_back(this->MtPath.empty() ? "mt" : this->MtPath); mtCommand.emplace_back("/nologo"); mtCommand.emplace_back("/manifest"); - if (this->LinkGeneratesManifest) { + + // add the linker generated manifest if the file exists. + if (this->LinkGeneratesManifest && + cmSystemTools::FileExists(this->LinkerManifestFile)) { mtCommand.push_back(this->LinkerManifestFile); } cm::append(mtCommand, this->UserManifests); diff --git a/Source/ctest.cxx b/Source/ctest.cxx index fbdf75ada..3b5bf8c4c 100644 --- a/Source/ctest.cxx +++ b/Source/ctest.cxx @@ -35,6 +35,7 @@ static const char* cmDocumentationOptions[][2] = { { "--output-on-failure", "Output anything outputted by the test program " "if the test should fail." }, + { "--stop-on-failure", "Stop running the tests after one has failed." }, { "--test-output-size-passed <size>", "Limit the output for passed tests " "to <size> bytes" }, diff --git a/Source/kwsys/Base64.c b/Source/kwsys/Base64.c index bf876f2d5..42650184a 100644 --- a/Source/kwsys/Base64.c +++ b/Source/kwsys/Base64.c @@ -130,7 +130,10 @@ size_t kwsysBase64_Encode(const unsigned char* input, size_t length, /* Decode 4 bytes into a 3 byte string. */ int kwsysBase64_Decode3(const unsigned char* src, unsigned char* dest) { - unsigned char d0, d1, d2, d3; + unsigned char d0; + unsigned char d1; + unsigned char d2; + unsigned char d3; d0 = kwsysBase64DecodeChar(src[0]); d1 = kwsysBase64DecodeChar(src[1]); diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 09bcdb943..b0a854292 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,309 +131,253 @@ 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_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 # capabilities and parent project's request. Enforce 0/1 as only # possible values for configuration into Configure.hxx. -# Check existence and uniqueness of long long and __int64. -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) - 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) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_LONG_AND___INT64 - "Checking whether long long and __int64 are the same type" DIRECT) - 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() - -# 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) +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() - -IF(KWSYS_USE_IOStream) - # Determine whether iostreams support 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) - 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() +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 +390,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 +438,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 +447,564 @@ 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() - 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 - COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOL=1) - 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 - COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOLL=1) - 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 - 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) - 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 - 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 - 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 - COMPILE_DEFINITIONS KWSYS_USE___INT64=1) - 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 - 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 - COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM___INT64=1) - ENDIF() - IF(KWSYS_BUILD_SHARED) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + endif() + endif() + 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) - -IF(NOT CMake_SOURCE_DIR) - SET(KWSYS_HXX_FILES ${KWSYS_HXX_FILES} - hashtable hash_fun hash_map hash_set - ) -ENDIF() +set(KWSYS_CLASSES) +set(KWSYS_H_FILES Configure SharedForward) +set(KWSYS_HXX_FILES Configure String) # Add selected C++ classes. -SET(cppclasses +set(cppclasses Directory DynamicLoader Encoding Glob RegularExpression SystemTools - CommandLineArguments IOStream FStream SystemInformation ConsoleBuf + CommandLineArguments 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 - testHashSTL.cxx - ) - ENDIF() - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + 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 +1019,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 +1064,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 +1073,71 @@ 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}) + #set(KWSYS_TEST_PROCESS_7 7) # uncomment to run timing-sensitive test locally + 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/CommandLineArguments.cxx b/Source/kwsys/CommandLineArguments.cxx index 3fd195561..e45db36ac 100644 --- a/Source/kwsys/CommandLineArguments.cxx +++ b/Source/kwsys/CommandLineArguments.cxx @@ -20,9 +20,9 @@ #include <sstream> #include <vector> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include <cstdio> +#include <cstdlib> +#include <cstring> #ifdef _MSC_VER # pragma warning(disable : 4786) @@ -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/Configure.h.in b/Source/kwsys/Configure.h.in index 5323c57be..8a237cea3 100644 --- a/Source/kwsys/Configure.h.in +++ b/Source/kwsys/Configure.h.in @@ -13,9 +13,6 @@ /* Disable some warnings inside kwsys source files. */ #if defined(KWSYS_NAMESPACE) -# if defined(__BORLANDC__) -# pragma warn - 8027 /* function not inlined. */ -# endif # if defined(__INTEL_COMPILER) # pragma warning(disable : 1572) /* floating-point equality test */ # endif @@ -68,11 +65,6 @@ # pragma warning(disable : 4710) /* function not inlined */ # pragma warning(disable : 4786) /* identifier truncated in debug info */ # endif -# if defined(__BORLANDC__) && !defined(__cplusplus) -/* Code has no effect; raised by winnt.h in C (not C++) when ignoring an - unused parameter using "(param)" syntax (i.e. no cast to void). */ -# pragma warn - 8019 -# endif #endif /* MSVC 6.0 in release mode will warn about code it produces with its diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx index e3791826b..0c2190aee 100644 --- a/Source/kwsys/Directory.cxx +++ b/Source/kwsys/Directory.cxx @@ -35,6 +35,18 @@ Directory::Directory() this->Internal = new DirectoryInternals; } +Directory::Directory(Directory&& other) +{ + this->Internal = other.Internal; + other.Internal = nullptr; +} + +Directory& Directory::operator=(Directory&& other) +{ + std::swap(this->Internal, other.Internal); + return *this; +} + Directory::~Directory() { delete this->Internal; @@ -80,26 +92,12 @@ void Directory::Clear() # include <sys/stat.h> # include <sys/types.h> -// Wide function names can vary depending on compiler: -# ifdef __BORLANDC__ -# define _wfindfirst_func __wfindfirst -# define _wfindnext_func __wfindnext -# else -# define _wfindfirst_func _wfindfirst -# define _wfindnext_func _wfindnext -# endif - namespace KWSYS_NAMESPACE { -bool Directory::Load(const std::string& name) +bool Directory::Load(const std::string& name, std::string* errorMessage) { this->Clear(); -# if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__) - // Older Visual C++ and Embarcadero compilers. - long srchHandle; -# else // Newer Visual C++ intptr_t srchHandle; -# endif char* buf; size_t n = name.size(); if (name.back() == '/' || name.back() == '\\') { @@ -118,8 +116,8 @@ bool Directory::Load(const std::string& name) struct _wfinddata_t data; // data of current file // Now put them into the file array - srchHandle = _wfindfirst_func( - (wchar_t*)Encoding::ToWindowsExtendedPath(buf).c_str(), &data); + srchHandle = + _wfindfirst((wchar_t*)Encoding::ToWindowsExtendedPath(buf).c_str(), &data); delete[] buf; if (srchHandle == -1) { @@ -129,19 +127,15 @@ bool Directory::Load(const std::string& name) // Loop through names do { this->Internal->Files.push_back(Encoding::ToNarrow(data.name)); - } while (_wfindnext_func(srchHandle, &data) != -1); + } while (_wfindnext(srchHandle, &data) != -1); this->Internal->Path = name; return _findclose(srchHandle) != -1; } -unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) +unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name, + std::string* errorMessage) { -# if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__) - // Older Visual C++ and Embarcadero compilers. - long srchHandle; -# else // Newer Visual C++ intptr_t srchHandle; -# endif char* buf; size_t n = name.size(); if (name.back() == '/') { @@ -154,8 +148,7 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) struct _wfinddata_t data; // data of current file // Now put them into the file array - srchHandle = - _wfindfirst_func((wchar_t*)Encoding::ToWide(buf).c_str(), &data); + srchHandle = _wfindfirst((wchar_t*)Encoding::ToWide(buf).c_str(), &data); delete[] buf; if (srchHandle == -1) { @@ -166,7 +159,7 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) unsigned long count = 0; do { count++; - } while (_wfindnext_func(srchHandle, &data) != -1); + } while (_wfindnext(srchHandle, &data) != -1); _findclose(srchHandle); return count; } @@ -180,6 +173,8 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) # include <sys/types.h> # include <dirent.h> +# include <errno.h> +# include <string.h> // PGI with glibc has trouble with dirent and large file support: // http://www.pgroup.com/userforum/viewtopic.php? @@ -197,29 +192,46 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) namespace KWSYS_NAMESPACE { -bool Directory::Load(const std::string& name) +bool Directory::Load(const std::string& name, std::string* errorMessage) { this->Clear(); + errno = 0; DIR* dir = opendir(name.c_str()); if (!dir) { - return 0; + if (errorMessage != nullptr) { + *errorMessage = std::string(strerror(errno)); + } + return false; } + errno = 0; for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { - this->Internal->Files.push_back(d->d_name); + this->Internal->Files.emplace_back(d->d_name); + } + if (errno != 0) { + if (errorMessage != nullptr) { + *errorMessage = std::string(strerror(errno)); + } + return false; } + this->Internal->Path = name; closedir(dir); - return 1; + return true; } -unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) +unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name, + std::string* errorMessage) { + errno = 0; DIR* dir = opendir(name.c_str()); if (!dir) { + if (errorMessage != nullptr) { + *errorMessage = std::string(strerror(errno)); + } return 0; } @@ -227,6 +239,13 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { count++; } + if (errno != 0) { + if (errorMessage != nullptr) { + *errorMessage = std::string(strerror(errno)); + } + return false; + } + closedir(dir); return count; } diff --git a/Source/kwsys/Directory.hxx.in b/Source/kwsys/Directory.hxx.in index ad8c51b86..7bc9db024 100644 --- a/Source/kwsys/Directory.hxx.in +++ b/Source/kwsys/Directory.hxx.in @@ -23,6 +23,11 @@ class @KWSYS_NAMESPACE@_EXPORT Directory { public: Directory(); + Directory(Directory&& other); + Directory(const Directory&) = delete; + Directory& operator=(const Directory&) = delete; + Directory& operator=(Directory&& other); + bool operator==(const Directory&) = delete; ~Directory(); /** @@ -30,7 +35,7 @@ public: * in that directory. 0 is returned if the directory can not be * opened, 1 if it is opened. */ - bool Load(const std::string&); + bool Load(const std::string&, std::string* errorMessage = nullptr); /** * Return the number of files in the current directory. @@ -41,7 +46,8 @@ public: * Return the number of files in the specified directory. * A higher performance static method. */ - static unsigned long GetNumberOfFilesInDirectory(const std::string&); + static unsigned long GetNumberOfFilesInDirectory( + const std::string&, std::string* errorMessage = nullptr); /** * Return the file at the given index, the indexing is 0 based @@ -62,10 +68,7 @@ public: private: // Private implementation details. DirectoryInternals* Internal; - - Directory(const Directory&); // Not implemented. - void operator=(const Directory&); // Not implemented. -}; // End Class: Directory +}; // End Class: Directory } // namespace @KWSYS_NAMESPACE@ diff --git a/Source/kwsys/DynamicLoader.cxx b/Source/kwsys/DynamicLoader.cxx index a4b864118..66ee9eafa 100644 --- a/Source/kwsys/DynamicLoader.cxx +++ b/Source/kwsys/DynamicLoader.cxx @@ -246,17 +246,6 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( // should have a tool to help get the symbol with the desired // calling convention. Currently we assume cdecl. // - // Borland: - // __cdecl = "_func" (default) - // __fastcall = "@_func" - // __stdcall = "func" - // - // Watcom: - // __cdecl = "_func" - // __fastcall = "@_func@X" - // __stdcall = "_func@X" - // __watcall = "func_" (default) - // // MSVC: // __cdecl = "func" (default) // __fastcall = "@_func@X" @@ -265,20 +254,9 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( // Note that the "@X" part of the name above is the total size (in // bytes) of the arguments on the stack. void* result; -# if defined(__BORLANDC__) || defined(__WATCOMC__) - // Need to prepend symbols with '_' - std::string ssym = '_' + sym; - const char* rsym = ssym.c_str(); -# else const char* rsym = sym.c_str(); -# endif result = (void*)GetProcAddress(lib, rsym); -// Hack to cast pointer-to-data to pointer-to-function. -# ifdef __WATCOMC__ - return *(DynamicLoader::SymbolPointer*)(&result); -# else return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result); -# endif } # define DYNLOAD_ERROR_BUFFER_SIZE 1024 diff --git a/Source/kwsys/EncodingCXX.cxx b/Source/kwsys/EncodingCXX.cxx index 5cad934ec..c68c73c8e 100644 --- a/Source/kwsys/EncodingCXX.cxx +++ b/Source/kwsys/EncodingCXX.cxx @@ -17,8 +17,8 @@ # include "Encoding.hxx.in" #endif -#include <stdlib.h> -#include <string.h> +#include <cstdlib> +#include <cstring> #include <vector> #ifdef _MSC_VER diff --git a/Source/kwsys/ExtraTest.cmake.in b/Source/kwsys/ExtraTest.cmake.in index e8c0a1cdb..4cec9e295 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/Glob.cxx b/Source/kwsys/Glob.cxx index 34bb0d0fe..5452f733b 100644 --- a/Source/kwsys/Glob.cxx +++ b/Source/kwsys/Glob.cxx @@ -23,9 +23,9 @@ #include <string> #include <vector> -#include <ctype.h> -#include <stdio.h> -#include <string.h> +#include <cctype> +#include <cstdio> +#include <cstring> namespace KWSYS_NAMESPACE { #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__) // On Windows and Apple, no difference between lower and upper case @@ -182,7 +182,15 @@ bool Glob::RecurseDirectory(std::string::size_type start, const std::string& dir, GlobMessages* messages) { kwsys::Directory d; - if (!d.Load(dir)) { + std::string errorMessage; + if (!d.Load(dir, &errorMessage)) { + if (messages) { + if (!errorMessage.empty()) { + messages->push_back(Message(Glob::warning, + "Error listing directory '" + dir + + "'! Reason: '" + errorMessage + "'")); + } + } return true; } unsigned long cc; @@ -278,7 +286,9 @@ void Glob::ProcessDirectory(std::string::size_type start, // std::cout << "ProcessDirectory: " << dir << std::endl; bool last = (start == this->Internals->Expressions.size() - 1); if (last && this->Recurse) { - this->RecurseDirectory(start, dir, messages); + if (kwsys::SystemTools::FileIsDirectory(dir)) { + this->RecurseDirectory(start, dir, messages); + } return; } @@ -385,10 +395,9 @@ bool Glob::FindFiles(const std::string& inexpr, GlobMessages* messages) } if (skip > 0) { - expr = expr.substr(skip); + expr.erase(0, skip); } - cexpr = ""; for (cc = 0; cc < expr.size(); cc++) { int ch = expr[cc]; if (ch == '/') { @@ -415,8 +424,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/Glob.hxx.in b/Source/kwsys/Glob.hxx.in index 170766f4b..b5a34d59a 100644 --- a/Source/kwsys/Glob.hxx.in +++ b/Source/kwsys/Glob.hxx.in @@ -28,6 +28,7 @@ public: enum MessageType { error, + warning, cyclicRecursion }; diff --git a/Source/kwsys/IOStream.cxx b/Source/kwsys/IOStream.cxx deleted file mode 100644 index e21f87d45..000000000 --- a/Source/kwsys/IOStream.cxx +++ /dev/null @@ -1,255 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Configure.hxx) - -// Include the streams library. -#include <iostream> -#include KWSYS_HEADER(IOStream.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Configure.hxx.in" -# include "IOStream.hxx.in" -#endif - -// Implement the rest of this file only if it is needed. -#if KWSYS_IOS_NEED_OPERATORS_LL - -# include <stdio.h> // sscanf, sprintf -# include <string.h> // memchr - -# if defined(_MAX_INT_DIG) -# define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG -# else -# define KWSYS_IOS_INT64_MAX_DIG 32 -# endif - -namespace KWSYS_NAMESPACE { - -// Scan an input stream for an integer value. -static int IOStreamScanStream(std::istream& is, char* buffer) -{ - // Prepare to write to buffer. - char* out = buffer; - char* end = buffer + KWSYS_IOS_INT64_MAX_DIG - 1; - - // Look for leading sign. - if (is.peek() == '+') { - *out++ = '+'; - is.ignore(); - } else if (is.peek() == '-') { - *out++ = '-'; - is.ignore(); - } - - // Determine the base. If not specified in the stream, try to - // detect it from the input. A leading 0x means hex, and a leading - // 0 alone means octal. - int base = 0; - int flags = is.flags() & std::ios_base::basefield; - if (flags == std::ios_base::oct) { - base = 8; - } else if (flags == std::ios_base::dec) { - base = 10; - } else if (flags == std::ios_base::hex) { - base = 16; - } - bool foundDigit = false; - bool foundNonZero = false; - if (is.peek() == '0') { - foundDigit = true; - is.ignore(); - if ((is.peek() == 'x' || is.peek() == 'X') && (base == 0 || base == 16)) { - base = 16; - foundDigit = false; - is.ignore(); - } else if (base == 0) { - base = 8; - } - } - - // Determine the range of digits allowed for this number. - const char* digits = "0123456789abcdefABCDEF"; - int maxDigitIndex = 10; - if (base == 8) { - maxDigitIndex = 8; - } else if (base == 16) { - maxDigitIndex = 10 + 6 + 6; - } - - // Scan until an invalid digit is found. - for (; is.peek() != EOF; is.ignore()) { - if (memchr(digits, *out = (char)is.peek(), maxDigitIndex) != 0) { - if ((foundNonZero || *out != '0') && out < end) { - ++out; - foundNonZero = true; - } - foundDigit = true; - } else { - break; - } - } - - // Correct the buffer contents for degenerate cases. - if (foundDigit && !foundNonZero) { - *out++ = '0'; - } else if (!foundDigit) { - out = buffer; - } - - // Terminate the string in the buffer. - *out = '\0'; - - return base; -} - -// Read an integer value from an input stream. -template <class T> -std::istream& IOStreamScanTemplate(std::istream& is, T& value, char type) -{ - int state = std::ios_base::goodbit; - - // Skip leading whitespace. - std::istream::sentry okay(is); - - if (okay) { - try { - // Copy the string to a buffer and construct the format string. - char buffer[KWSYS_IOS_INT64_MAX_DIG]; -# if defined(_MSC_VER) - char format[] = "%I64_"; - const int typeIndex = 4; -# else - char format[] = "%ll_"; - const int typeIndex = 3; -# endif - switch (IOStreamScanStream(is, buffer)) { - case 8: - format[typeIndex] = 'o'; - break; - case 0: // Default to decimal if not told otherwise. - case 10: - format[typeIndex] = type; - break; - case 16: - format[typeIndex] = 'x'; - break; - }; - - // Use sscanf to parse the number from the buffer. - T result; - int success = (sscanf(buffer, format, &result) == 1) ? 1 : 0; - - // Set flags for resulting state. - if (is.peek() == EOF) { - state |= std::ios_base::eofbit; - } - if (!success) { - state |= std::ios_base::failbit; - } else { - value = result; - } - } catch (...) { - state |= std::ios_base::badbit; - } - } - - is.setstate(std::ios_base::iostate(state)); - return is; -} - -// Print an integer value to an output stream. -template <class T> -std::ostream& IOStreamPrintTemplate(std::ostream& os, T value, char type) -{ - std::ostream::sentry okay(os); - if (okay) { - try { - // Construct the format string. - char format[8]; - char* f = format; - *f++ = '%'; - if (os.flags() & std::ios_base::showpos) { - *f++ = '+'; - } - if (os.flags() & std::ios_base::showbase) { - *f++ = '#'; - } -# if defined(_MSC_VER) - *f++ = 'I'; - *f++ = '6'; - *f++ = '4'; -# else - *f++ = 'l'; - *f++ = 'l'; -# endif - long bflags = os.flags() & std::ios_base::basefield; - if (bflags == std::ios_base::oct) { - *f++ = 'o'; - } else if (bflags != std::ios_base::hex) { - *f++ = type; - } else if (os.flags() & std::ios_base::uppercase) { - *f++ = 'X'; - } else { - *f++ = 'x'; - } - *f = '\0'; - - // Use sprintf to print to a buffer and then write the - // buffer to the stream. - char buffer[2 * KWSYS_IOS_INT64_MAX_DIG]; - sprintf(buffer, format, value); - os << buffer; - } catch (...) { - os.clear(os.rdstate() | std::ios_base::badbit); - } - } - return os; -} - -# if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG -// Implement input stream operator for IOStreamSLL. -std::istream& IOStreamScan(std::istream& is, IOStreamSLL& value) -{ - return IOStreamScanTemplate(is, value, 'd'); -} - -// Implement input stream operator for IOStreamULL. -std::istream& IOStreamScan(std::istream& is, IOStreamULL& value) -{ - return IOStreamScanTemplate(is, value, 'u'); -} -# endif - -# if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG -// Implement output stream operator for IOStreamSLL. -std::ostream& IOStreamPrint(std::ostream& os, IOStreamSLL value) -{ - return IOStreamPrintTemplate(os, value, 'd'); -} - -// Implement output stream operator for IOStreamULL. -std::ostream& IOStreamPrint(std::ostream& os, IOStreamULL value) -{ - return IOStreamPrintTemplate(os, value, 'u'); -} -# endif - -} // namespace KWSYS_NAMESPACE - -#else - -namespace KWSYS_NAMESPACE { - -// Create one public symbol in this object file to avoid warnings from -// archivers. -void IOStreamSymbolToAvoidWarning(); -void IOStreamSymbolToAvoidWarning() -{ -} - -} // namespace KWSYS_NAMESPACE - -#endif // KWSYS_IOS_NEED_OPERATORS_LL diff --git a/Source/kwsys/IOStream.hxx.in b/Source/kwsys/IOStream.hxx.in deleted file mode 100644 index db8a23ef5..000000000 --- a/Source/kwsys/IOStream.hxx.in +++ /dev/null @@ -1,126 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_IOStream_hxx -#define @KWSYS_NAMESPACE@_IOStream_hxx - -#include <iosfwd> - -/* Define these macros temporarily to keep the code readable. */ -#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif - -/* Whether istream supports long long. */ -#define @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG \ - @KWSYS_IOS_HAS_ISTREAM_LONG_LONG@ - -/* Whether ostream supports long long. */ -#define @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG \ - @KWSYS_IOS_HAS_OSTREAM_LONG_LONG@ - -/* Determine whether we need to define the streaming operators for - long long or __int64. */ -#if @KWSYS_USE_LONG_LONG@ -# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG || \ - !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG -# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1 -namespace @KWSYS_NAMESPACE@ { -typedef long long IOStreamSLL; -typedef unsigned long long IOStreamULL; -} -# endif -#elif defined(_MSC_VER) && _MSC_VER < 1300 -# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1 -namespace @KWSYS_NAMESPACE@ { -typedef __int64 IOStreamSLL; -typedef unsigned __int64 IOStreamULL; -} -#endif -#if !defined(@KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL) -# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 0 -#endif - -#if @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL -# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG - -/* Input stream operator implementation functions. */ -namespace @KWSYS_NAMESPACE@ { -kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamSLL&); -kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamULL&); -} - -/* Provide input stream operator for long long. */ -# if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_LONG_LONG) && \ - !defined(KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED) -# define KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED -# define @KWSYS_NAMESPACE@_IOS_ISTREAM_LONG_LONG_DEFINED -inline std::istream& operator>>(std::istream& is, - @KWSYS_NAMESPACE@::IOStreamSLL& value) -{ - return @KWSYS_NAMESPACE@::IOStreamScan(is, value); -} -# endif - -/* Provide input stream operator for unsigned long long. */ -# if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_UNSIGNED_LONG_LONG) && \ - !defined(KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED) -# define KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED -# define @KWSYS_NAMESPACE@_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED -inline std::istream& operator>>(std::istream& is, - @KWSYS_NAMESPACE@::IOStreamULL& value) -{ - return @KWSYS_NAMESPACE@::IOStreamScan(is, value); -} -# endif -# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG */ - -# if !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG - -/* Output stream operator implementation functions. */ -namespace @KWSYS_NAMESPACE@ { -kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamSLL); -kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamULL); -} - -/* Provide output stream operator for long long. */ -# if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_LONG_LONG) && \ - !defined(KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED) -# define KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED -# define @KWSYS_NAMESPACE@_IOS_OSTREAM_LONG_LONG_DEFINED -inline std::ostream& operator<<(std::ostream& os, - @KWSYS_NAMESPACE@::IOStreamSLL value) -{ - return @KWSYS_NAMESPACE@::IOStreamPrint(os, value); -} -# endif - -/* Provide output stream operator for unsigned long long. */ -# if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_UNSIGNED_LONG_LONG) && \ - !defined(KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED) -# define KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED -# define @KWSYS_NAMESPACE@_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED -inline std::ostream& operator<<(std::ostream& os, - @KWSYS_NAMESPACE@::IOStreamULL value) -{ - return @KWSYS_NAMESPACE@::IOStreamPrint(os, value); -} -# endif -# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG */ -#endif /* @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL */ - -/* Undefine temporary macros. */ -#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# undef kwsysEXPORT -#endif - -/* If building a C++ file in kwsys itself, give the source file - access to the macros without a configured namespace. */ -#if defined(KWSYS_NAMESPACE) -# define KWSYS_IOS_HAS_ISTREAM_LONG_LONG \ - @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG -# define KWSYS_IOS_HAS_OSTREAM_LONG_LONG \ - @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG -# define KWSYS_IOS_NEED_OPERATORS_LL @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL -#endif - -#endif diff --git a/Source/kwsys/MD5.c b/Source/kwsys/MD5.c index 97cf9ba68..fb18a5bba 100644 --- a/Source/kwsys/MD5.c +++ b/Source/kwsys/MD5.c @@ -171,8 +171,10 @@ typedef struct md5_state_s static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/) { - md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], - d = pms->abcd[3]; + md5_word_t a = pms->abcd[0]; + md5_word_t b = pms->abcd[1]; + md5_word_t c = pms->abcd[2]; + md5_word_t d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ @@ -227,9 +229,10 @@ static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/) # else # define xbuf X /* (static only) */ # endif - for (i = 0; i < 16; ++i, xp += 4) + for (i = 0; i < 16; ++i, xp += 4) { xbuf[i] = (md5_word_t)(xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24)); + } } #endif } @@ -367,34 +370,39 @@ static void md5_append(md5_state_t* pms, const md5_byte_t* data, size_t nbytes) size_t offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); - if (nbytes <= 0) + if (nbytes <= 0) { return; + } /* Update the message length. */ pms->count[1] += (md5_word_t)(nbytes >> 29); pms->count[0] += nbits; - if (pms->count[0] < nbits) + if (pms->count[0] < nbits) { pms->count[1]++; + } /* Process an initial partial block. */ if (offset) { size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) + if (offset + copy < 64) { return; + } p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) + for (; left >= 64; p += 64, left -= 64) { md5_process(pms, p); + } /* Process a final partial block. */ - if (left) + if (left) { memcpy(pms->buf, p, left); + } } /* Finish the message and return the digest. */ @@ -409,14 +417,16 @@ static void md5_finish(md5_state_t* pms, md5_byte_t digest[16]) int i; /* Save the length before padding. */ - for (i = 0; i < 8; ++i) + for (i = 0; i < 8; ++i) { data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + } /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) { digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); + } } #if defined(__clang__) && !defined(__INTEL_COMPILER) diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in index 73ea9dbfc..9f2162b3d 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 f65690b31..cc4552913 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); @@ -431,8 +432,8 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command) char const* const* c = command; kwsysProcess_ptrdiff_t n = 0; kwsysProcess_ptrdiff_t i = 0; - while (*c++) - ; + while (*c++) { + } n = c - command - 1; newCommands[cp->NumberOfCommands] = (char**)malloc((size_t)(n + 1) * sizeof(char*)); @@ -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; @@ -684,7 +685,8 @@ const char* kwsysProcess_GetErrorString(kwsysProcess* cp) { if (!cp) { return "Process management structure could not be allocated"; - } else if (cp->State == kwsysProcess_State_Error) { + } + if (cp->State == kwsysProcess_State_Error) { return cp->ErrorMessage; } return "Success"; @@ -694,7 +696,8 @@ const char* kwsysProcess_GetExceptionString(kwsysProcess* cp) { if (!(cp && cp->ProcessResults && (cp->NumberOfCommands > 0))) { return "GetExceptionString called with NULL process management structure"; - } else if (cp->State == kwsysProcess_State_Exception) { + } + if (cp->State == kwsysProcess_State_Exception) { return cp->ProcessResults[cp->NumberOfCommands - 1].ExitExceptionString; } return "No exception"; @@ -786,8 +789,8 @@ void kwsysProcess_Execute(kwsysProcess* cp) /* Some platforms specify that the chdir call may be interrupted. Repeat the call until it finishes. */ - while (((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR)) - ; + while (((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR)) { + } if (r < 0) { kwsysProcessCleanup(cp, 1); return; @@ -1013,8 +1016,8 @@ void kwsysProcess_Execute(kwsysProcess* cp) if (cp->RealWorkingDirectory) { /* Some platforms specify that the chdir call may be interrupted. Repeat the call until it finishes. */ - while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR)) - ; + while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR)) { + } free(cp->RealWorkingDirectory); cp->RealWorkingDirectory = 0; } @@ -1099,22 +1102,22 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length, if (wd.PipeId) { /* Data are ready on a pipe. */ return wd.PipeId; - } else if (wd.Expired) { + } + if (wd.Expired) { /* A timeout has expired. */ if (wd.User) { /* The user timeout has expired. It has no time left. */ return kwsysProcess_Pipe_Timeout; - } else { - /* The process timeout has expired. Kill the children now. */ - kwsysProcess_Kill(cp); - cp->Killed = 0; - cp->TimeoutExpired = 1; - return kwsysProcess_Pipe_None; } - } else { - /* No pipes are left open. */ + + /* The process timeout has expired. Kill the children now. */ + kwsysProcess_Kill(cp); + cp->Killed = 0; + cp->TimeoutExpired = 1; return kwsysProcess_Pipe_None; } + /* No pipes are left open. */ + return kwsysProcess_Pipe_None; } static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length, @@ -1144,8 +1147,8 @@ static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length, read until the operation is not interrupted. */ while (((n = read(cp->PipeReadEnds[i], cp->PipeBuffer, KWSYSPE_PIPE_BUFFER_SIZE)) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } if (n > 0) { /* We have data on this pipe. */ if (i == KWSYSPE_PIPE_SIGNAL) { @@ -1183,7 +1186,7 @@ static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length, /* Make sure the set is empty (it should always be empty here anyway). */ - FD_ZERO(&cp->PipeSet); + FD_ZERO(&cp->PipeSet); // NOLINT(readability-isolate-declaration) /* Setup a timeout if required. */ if (wd->TimeoutTime.tv_sec < 0) { @@ -1218,15 +1221,16 @@ static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length, /* Run select to block until data are available. Repeat call until it is not interrupted. */ while (((numReady = select(max + 1, &cp->PipeSet, 0, 0, timeout)) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } /* Check result of select. */ if (numReady == 0) { /* Select's timeout expired. */ wd->Expired = 1; return 1; - } else if (numReady < 0) { + } + if (numReady < 0) { /* Select returned an error. Leave the error description in the pipe buffer. */ strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); @@ -1366,11 +1370,13 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) cp->ProcessResults[prPipe].State = kwsysProcess_StateByIndex_Exited; cp->ProcessResults[prPipe].ExitException = kwsysProcess_Exception_None; cp->ProcessResults[prPipe].ExitValue = + // NOLINTNEXTLINE(google-readability-casting) (int)WEXITSTATUS(cp->ProcessResults[prPipe].ExitCode); } else if (WIFSIGNALED(cp->ProcessResults[prPipe].ExitCode)) { /* The child received an unhandled signal. */ cp->ProcessResults[prPipe].State = kwsysProcess_State_Exception; kwsysProcessSetExitExceptionByIndex( + // NOLINTNEXTLINE(google-readability-casting) cp, (int)WTERMSIG(cp->ProcessResults[prPipe].ExitCode), prPipe); } else { /* Error getting the child return code. */ @@ -1449,8 +1455,8 @@ void kwsysProcess_Kill(kwsysProcess* cp) /* Reap the child. Keep trying until the call is not interrupted. */ - while ((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && (errno == EINTR)) - ; + while ((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && (errno == EINTR)) { + } } } @@ -1501,7 +1507,7 @@ static int kwsysProcessInitialize(kwsysProcess* cp) cp->PipesLeft = 0; cp->CommandsLeft = 0; #if KWSYSPE_USE_SELECT - FD_ZERO(&cp->PipeSet); + FD_ZERO(&cp->PipeSet); // NOLINT(readability-isolate-declaration) #endif cp->State = kwsysProcess_State_Starting; cp->Killed = 0; @@ -1590,16 +1596,16 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error) /* Reap the child. Keep trying until the call is not interrupted. */ while ((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } } } } /* Restore the working directory. */ if (cp->RealWorkingDirectory) { - while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR)) - ; + while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR)) { + } } } @@ -1635,8 +1641,8 @@ static void kwsysProcessCleanupDescriptor(int* pfd) if (pfd && *pfd > 2) { /* Keep trying to close until it is not interrupted by a * signal. */ - while ((close(*pfd) < 0) && (errno == EINTR)) - ; + while ((close(*pfd) < 0) && (errno == EINTR)) { + } *pfd = -1; } } @@ -1661,8 +1667,8 @@ static void kwsysProcessClosePipes(kwsysProcess* cp) read until the operation is not interrupted. */ while ((read(cp->PipeReadEnds[i], cp->PipeBuffer, KWSYSPE_PIPE_BUFFER_SIZE) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } } #endif @@ -1689,7 +1695,8 @@ int decc$set_child_standard_streams(int fd1, int fd2, int fd3); static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, kwsysProcessCreateInformation* si) { - sigset_t mask, old_mask; + sigset_t mask; + sigset_t old_mask; int pgidPipe[2]; char tmp; ssize_t readRes; @@ -1817,8 +1824,8 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, /* Make sure the child is in the process group before we proceed. This avoids race conditions with calls to the kill function that we make for signalling process groups. */ - while ((readRes = read(pgidPipe[0], &tmp, 1)) > 0) - ; + while ((readRes = read(pgidPipe[0], &tmp, 1)) > 0) { + } if (readRes < 0) { sigprocmask(SIG_SETMASK, &old_mask, 0); kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); @@ -1846,8 +1853,8 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, /* Keep trying to read until the operation is not interrupted. */ while (((n = read(si->ErrorPipe[0], cp->ErrorMessage + total, (size_t)(KWSYSPE_PIPE_BUFFER_SIZE - total))) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } if (n > 0) { total += n; } @@ -1872,7 +1879,8 @@ static void kwsysProcessDestroy(kwsysProcess* cp) int i; /* Temporarily disable signals that access ForkPIDs. We don't want them to read a reaped PID, and writes to ForkPIDs are not atomic. */ - sigset_t mask, old_mask; + sigset_t mask; + sigset_t old_mask; sigemptyset(&mask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); @@ -1885,8 +1893,8 @@ static void kwsysProcessDestroy(kwsysProcess* cp) int result; while (((result = waitpid(cp->ForkPIDs[i], &cp->CommandExitCodes[i], WNOHANG)) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } if (result > 0) { /* This child has termianted. */ cp->ForkPIDs[i] = 0; @@ -1959,7 +1967,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,35 +2000,33 @@ 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) { if (timeoutTime->tv_sec < 0) { /* No timeout time has been requested. */ return 0; - } else { - /* Calculate the remaining time. */ - kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); - kwsysProcessTime timeLeft = - kwsysProcessTimeSubtract(*timeoutTime, currentTime); - if (timeLeft.tv_sec < 0 && userTimeout && *userTimeout <= 0) { - /* Caller has explicitly requested a zero timeout. */ - timeLeft.tv_sec = 0; - timeLeft.tv_usec = 0; - } + } + /* Calculate the remaining time. */ + kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); + kwsysProcessTime timeLeft = + kwsysProcessTimeSubtract(*timeoutTime, currentTime); + if (timeLeft.tv_sec < 0 && userTimeout && *userTimeout <= 0) { + /* Caller has explicitly requested a zero timeout. */ + timeLeft.tv_sec = 0; + timeLeft.tv_usec = 0; + } - if (timeLeft.tv_sec < 0 || - (timeLeft.tv_sec == 0 && timeLeft.tv_usec == 0 && zeroIsExpired)) { - /* Timeout has already expired. */ - return 1; - } else { - /* There is some time left. */ - timeoutLength->tv_sec = timeLeft.tv_sec; - timeoutLength->tv_usec = timeLeft.tv_usec; - return 0; - } + if (timeLeft.tv_sec < 0 || + (timeLeft.tv_sec == 0 && timeLeft.tv_usec == 0 && zeroIsExpired)) { + /* Timeout has already expired. */ + return 1; } + /* There is some time left. */ + timeoutLength->tv_sec = timeLeft.tv_sec; + timeoutLength->tv_usec = timeLeft.tv_usec; + return 0; } static kwsysProcessTime kwsysProcessTimeGetCurrent(void) @@ -2424,41 +2431,39 @@ static pid_t kwsysProcessFork(kwsysProcess* cp, if (middle_pid < 0) { /* Fork failed. Return as if we were not detaching. */ return middle_pid; - } else if (middle_pid == 0) { + } + if (middle_pid == 0) { /* This is the intermediate process. Create the real child. */ pid_t child_pid = fork(); if (child_pid == 0) { /* This is the real child process. There is nothing to do here. */ return 0; - } else { - /* Use the error pipe to report the pid to the real parent. */ - while ((write(si->ErrorPipe[1], &child_pid, sizeof(child_pid)) < 0) && - (errno == EINTR)) - ; - - /* Exit without cleanup. The parent holds all resources. */ - kwsysProcessExit(); - return 0; /* Never reached, but avoids SunCC warning. */ } - } else { - /* This is the original parent process. The intermediate - process will use the error pipe to report the pid of the - detached child. */ - pid_t child_pid; - int status; - while ((read(si->ErrorPipe[0], &child_pid, sizeof(child_pid)) < 0) && - (errno == EINTR)) - ; + /* Use the error pipe to report the pid to the real parent. */ + while ((write(si->ErrorPipe[1], &child_pid, sizeof(child_pid)) < 0) && + (errno == EINTR)) { + } - /* Wait for the intermediate process to exit and clean it up. */ - while ((waitpid(middle_pid, &status, 0) < 0) && (errno == EINTR)) - ; - return child_pid; + /* Exit without cleanup. The parent holds all resources. */ + kwsysProcessExit(); + return 0; /* Never reached, but avoids SunCC warning. */ } - } else { - /* Not creating a detached process. Use normal fork. */ - return fork(); + /* This is the original parent process. The intermediate + process will use the error pipe to report the pid of the + detached child. */ + pid_t child_pid; + int status; + while ((read(si->ErrorPipe[0], &child_pid, sizeof(child_pid)) < 0) && + (errno == EINTR)) { + } + + /* Wait for the intermediate process to exit and clean it up. */ + while ((waitpid(middle_pid, &status, 0) < 0) && (errno == EINTR)) { + } + return child_pid; } + /* Not creating a detached process. Use normal fork. */ + return fork(); } #endif @@ -2563,7 +2568,8 @@ static void kwsysProcessKill(pid_t process_id) /* Make sure the process started and provided a valid header. */ if (ps && fscanf(ps, "%*[^\n]\n") != EOF) { /* Look for processes whose parent is the process being killed. */ - int pid, ppid; + int pid; + int ppid; while (fscanf(ps, KWSYSPE_PS_FORMAT, &pid, &ppid) == 2) { if (ppid == process_id) { /* Recursively kill this child and its children. */ @@ -2725,8 +2731,8 @@ static int kwsysProcessesAdd(kwsysProcess* cp) sigemptyset(&newSigAction.sa_mask); while ((sigaction(SIGCHLD, &newSigAction, &kwsysProcessesOldSigChldAction) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } /* Install our handler for SIGINT / SIGTERM. Repeat call until it is not interrupted. */ @@ -2734,15 +2740,15 @@ static int kwsysProcessesAdd(kwsysProcess* cp) sigaddset(&newSigAction.sa_mask, SIGTERM); while ((sigaction(SIGINT, &newSigAction, &kwsysProcessesOldSigIntAction) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } sigemptyset(&newSigAction.sa_mask); sigaddset(&newSigAction.sa_mask, SIGINT); while ((sigaction(SIGTERM, &newSigAction, &kwsysProcessesOldSigIntAction) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } } } @@ -2773,14 +2779,14 @@ static void kwsysProcessesRemove(kwsysProcess* cp) /* Restore the signal handlers. Repeat call until it is not interrupted. */ while ((sigaction(SIGCHLD, &kwsysProcessesOldSigChldAction, 0) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } while ((sigaction(SIGINT, &kwsysProcessesOldSigIntAction, 0) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } while ((sigaction(SIGTERM, &kwsysProcessesOldSigTermAction, 0) < 0) && - (errno == EINTR)) - ; + (errno == EINTR)) { + } /* Free the table of process pointers since it is now empty. This is safe because the signal handler has been removed. */ @@ -2806,7 +2812,10 @@ static void kwsysProcessesSignalHandler(int signum #endif ) { - int i, j, procStatus, old_errno = errno; + int i; + int j; + int procStatus; + int old_errno = errno; #if KWSYSPE_USE_SIGINFO (void)info; (void)ucontext; @@ -2863,8 +2872,8 @@ static void kwsysProcessesSignalHandler(int signum memset(&defSigAction, 0, sizeof(defSigAction)); defSigAction.sa_handler = SIG_DFL; sigemptyset(&defSigAction.sa_mask); - while ((sigaction(signum, &defSigAction, 0) < 0) && (errno == EINTR)) - ; + while ((sigaction(signum, &defSigAction, 0) < 0) && (errno == EINTR)) { + } /* Unmask the signal. */ sigemptyset(&unblockSet); sigaddset(&unblockSet, signum); diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index 68c52185e..12670762d 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -31,9 +31,6 @@ a UNIX-style select system call. #include <io.h> /* _unlink */ #include <stdio.h> /* sprintf */ #include <string.h> /* strlen, strdup */ -#ifdef __WATCOMC__ -# define _unlink unlink -#endif #ifndef _MAX_FNAME # define _MAX_FNAME 4096 @@ -48,11 +45,6 @@ a UNIX-style select system call. # pragma warning(disable : 4706) #endif -#if defined(__BORLANDC__) -# pragma warn - 8004 /* assigned a value that is never used */ -# pragma warn - 8060 /* Assignment inside if() condition. */ -#endif - /* There are pipes for the process pipeline's stdout and stderr. */ #define KWSYSPE_PIPE_COUNT 2 #define KWSYSPE_PIPE_STDOUT 0 @@ -761,7 +753,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.cxx b/Source/kwsys/RegularExpression.cxx index 5e6f8da50..4f74eba53 100644 --- a/Source/kwsys/RegularExpression.cxx +++ b/Source/kwsys/RegularExpression.cxx @@ -28,8 +28,8 @@ # include "RegularExpression.hxx.in" #endif -#include <stdio.h> -#include <string.h> +#include <cstdio> +#include <cstring> namespace KWSYS_NAMESPACE { @@ -367,8 +367,7 @@ bool RegularExpression::compile(const char* exp) // Allocate space. //#ifndef _WIN32 - if (this->program != nullptr) - delete[] this->program; + delete[] this->program; //#endif this->program = new char[comp.regsize]; this->progsize = static_cast<int>(comp.regsize); diff --git a/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in index d11db8828..2709cde5f 100644 --- a/Source/kwsys/RegularExpression.hxx.in +++ b/Source/kwsys/RegularExpression.hxx.in @@ -26,12 +26,6 @@ #include <string> -/* Disable useless Borland warnings. KWSys tries not to force things - on its includers, but there is no choice here. */ -#if defined(__BORLANDC__) -# pragma warn - 8027 /* function not inlined. */ -#endif - namespace @KWSYS_NAMESPACE@ { // Forward declaration diff --git a/Source/kwsys/SharedForward.h.in b/Source/kwsys/SharedForward.h.in index 5716cd4f1..091334b75 100644 --- a/Source/kwsys/SharedForward.h.in +++ b/Source/kwsys/SharedForward.h.in @@ -66,12 +66,6 @@ # endif # endif -# if defined(__BORLANDC__) && !defined(__cplusplus) -/* Code has no effect; raised by winnt.h in C (not C++) when ignoring an - unused parameter using "(param)" syntax (i.e. no cast to void). */ -# pragma warn - 8019 -# endif - /* Full path to the directory in which this executable is built. Do not include a trailing slash. */ # if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD) diff --git a/Source/kwsys/String.hxx.in b/Source/kwsys/String.hxx.in index db1cf22a9..c36f4ce4a 100644 --- a/Source/kwsys/String.hxx.in +++ b/Source/kwsys/String.hxx.in @@ -52,14 +52,6 @@ public: } }; // End Class: String -#if defined(__WATCOMC__) -inline bool operator<(String const& l, String const& r) -{ - return (static_cast<std::string const&>(l) < - static_cast<std::string const&>(r)); -} -#endif - } // namespace @KWSYS_NAMESPACE@ #endif diff --git a/Source/kwsys/System.c b/Source/kwsys/System.c index d43cc6fbb..dbfd2fd16 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 6ec6e48ff..ed1cdc0ab 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -64,9 +64,9 @@ typedef int siginfo_t; #else # include <sys/types.h> -# include <errno.h> // extern int errno; +# include <cerrno> // extern int errno; +# include <csignal> # include <fcntl.h> -# include <signal.h> # include <sys/resource.h> // getrlimit # include <sys/time.h> # include <sys/utsname.h> // int uname(struct utsname *buf); @@ -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; @@ -163,39 +163,11 @@ typedef struct rlimit ResourceLimitType; # undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP #endif -#include <ctype.h> // int isdigit(int c); +#include <cctype> // int isdigit(int c); +#include <cstdio> +#include <cstdlib> +#include <cstring> #include <memory.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#if defined(KWSYS_USE_LONG_LONG) -# if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) -# define iostreamLongLong(x) (x) -# else -# define iostreamLongLong(x) ((long)(x)) -# endif -#elif defined(KWSYS_USE___INT64) -# if defined(KWSYS_IOS_HAS_OSTREAM___INT64) -# define iostreamLongLong(x) (x) -# else -# define iostreamLongLong(x) ((long)(x)) -# endif -#else -# error "No Long Long" -#endif - -#if defined(KWSYS_CXX_HAS_ATOLL) -# define atoLongLong atoll -#else -# if defined(KWSYS_CXX_HAS__ATOI64) -# define atoLongLong _atoi64 -# elif defined(KWSYS_CXX_HAS_ATOL) -# define atoLongLong atol -# else -# define atoLongLong atoi -# endif -#endif #if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) && \ !defined(__clang__) @@ -204,15 +176,15 @@ typedef struct rlimit ResourceLimitType; # define USE_ASM_INSTRUCTIONS 0 #endif -#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__) +#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__) && \ + !defined(_M_ARM64) # include <intrin.h> # define USE_CPUID_INTRINSICS 1 #else # define USE_CPUID_INTRINSICS 0 #endif -#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS || \ - defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) +#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS # define USE_CPUID 1 #else # define USE_CPUID 0 @@ -272,21 +244,6 @@ static bool call_cpuid(int select, int result[4]) } memcpy(result, tmp, sizeof(tmp)); -# elif defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) - unsigned int a, b, c, d; - __asm { - mov EAX, select; - cpuid - mov a, EAX; - mov b, EBX; - mov c, ECX; - mov d, EDX; - } - - result[0] = a; - result[1] = b; - result[2] = c; - result[3] = d; # endif // The cpuid instruction succeeded. @@ -303,34 +260,33 @@ 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; 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,29 +295,29 @@ 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(); + long long GetProcessId(); // Retrieve memory information in KiB. - LongLong GetHostMemoryTotal(); - LongLong GetHostMemoryAvailable(const char* envVarName); - LongLong GetHostMemoryUsed(); + long long GetHostMemoryTotal(); + long long GetHostMemoryAvailable(const char* hostLimitEnvVarName); + long long GetHostMemoryUsed(); - LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName, - const char* procLimitEnvVarName); - LongLong GetProcMemoryUsed(); + long long GetProcMemoryAvailable(const char* hostLimitEnvVarName, + const char* procLimitEnvVarName); + long long GetProcMemoryUsed(); double GetLoadAverage(); @@ -377,60 +333,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,8 +475,9 @@ protected: void CPUCountWindows(); // For windows unsigned char GetAPICId(); // For windows - bool IsSMTSupported(); - static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); // For windows + bool IsSMTSupported() const; + static long long GetCyclesDifference(DELAY_FUNC, + unsigned int); // For windows // For Linux and Cygwin, /proc/cpuinfo formats are slightly different bool RetreiveInformationFromCpuInfoFile(); @@ -768,42 +768,41 @@ std::string SystemInformation::GetMemoryDescription( const char* hostLimitEnvVarName, const char* procLimitEnvVarName) { std::ostringstream oss; - oss << "Host Total: " << iostreamLongLong(this->GetHostMemoryTotal()) + oss << "Host Total: " << this->GetHostMemoryTotal() << " KiB, Host Available: " - << iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName)) + << this->GetHostMemoryAvailable(hostLimitEnvVarName) << " KiB, Process Available: " - << iostreamLongLong(this->GetProcMemoryAvailable(hostLimitEnvVarName, - procLimitEnvVarName)) + << this->GetProcMemoryAvailable(hostLimitEnvVarName, procLimitEnvVarName) << " KiB"; return oss.str(); } // host memory info in units of KiB. -SystemInformation::LongLong SystemInformation::GetHostMemoryTotal() +long long SystemInformation::GetHostMemoryTotal() { return this->Implementation->GetHostMemoryTotal(); } -SystemInformation::LongLong SystemInformation::GetHostMemoryAvailable( +long long SystemInformation::GetHostMemoryAvailable( const char* hostLimitEnvVarName) { return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName); } -SystemInformation::LongLong SystemInformation::GetHostMemoryUsed() +long long SystemInformation::GetHostMemoryUsed() { return this->Implementation->GetHostMemoryUsed(); } // process memory info in units of KiB. -SystemInformation::LongLong SystemInformation::GetProcMemoryAvailable( +long long SystemInformation::GetProcMemoryAvailable( const char* hostLimitEnvVarName, const char* procLimitEnvVarName) { return this->Implementation->GetProcMemoryAvailable(hostLimitEnvVarName, procLimitEnvVarName); } -SystemInformation::LongLong SystemInformation::GetProcMemoryUsed() +long long SystemInformation::GetProcMemoryUsed() { return this->Implementation->GetProcMemoryUsed(); } @@ -813,7 +812,7 @@ double SystemInformation::GetLoadAverage() return this->Implementation->GetLoadAverage(); } -SystemInformation::LongLong SystemInformation::GetProcessId() +long long SystemInformation::GetProcessId() { return this->Implementation->GetProcessId(); } @@ -885,7 +884,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 +898,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); @@ -1322,9 +1321,9 @@ std::string SymbolProperties::GetFileName(const std::string& path) const { std::string file(path); if (!this->ReportPath) { - size_t at = file.rfind("/"); + size_t at = file.rfind('/'); if (at != std::string::npos) { - file = file.substr(at + 1); + file.erase(0, at + 1); } } return file; @@ -1464,10 +1463,6 @@ SystemInformationImplementation::SystemInformationImplementation() this->OSIs64Bit = (sizeof(void*) == 8); } -SystemInformationImplementation::~SystemInformationImplementation() -{ -} - void SystemInformationImplementation::RunCPUCheck() { #ifdef _WIN32 @@ -1564,7 +1559,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 +1755,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 +1763,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 +1771,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 +1779,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 +1793,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 +1845,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; @@ -2128,7 +2126,7 @@ void SystemInformationImplementation::FindManufacturer( this->ChipManufacturer = HP; // Hewlett-Packard else if (this->ChipID.Vendor == "Motorola") this->ChipManufacturer = Motorola; // Motorola Microelectronics - else if (family.substr(0, 7) == "PA-RISC") + else if (family.compare(0, 7, "PA-RISC") == 0) this->ChipManufacturer = HP; // Hewlett-Packard else this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer @@ -2843,7 +2841,7 @@ static void SystemInformationStripLeadingSpace(std::string& str) // post-process the name. std::string::size_type pos = str.find_first_not_of(" "); if (pos != std::string::npos) { - str = str.substr(pos); + str.erase(0, pos); } } #endif @@ -3344,8 +3342,8 @@ std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile( size_t pos = buffer.find(word, init); if (pos != std::string::npos) { this->CurrentPositionInFile = pos; - pos = buffer.find(":", pos); - size_t pos2 = buffer.find("\n", pos); + pos = buffer.find(':', pos); + size_t pos2 = buffer.find('\n', pos); if (pos != std::string::npos && pos2 != std::string::npos) { // It may happen that the beginning matches, but this is still not the // requested key. @@ -3358,7 +3356,9 @@ std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile( return this->ExtractValueFromCpuInfoFile(buffer, word, pos2); } } - return buffer.substr(pos + 2, pos2 - pos - 2); + buffer.erase(0, pos + 2); + buffer.resize(pos2 - pos - 2); + return buffer; } } this->CurrentPositionInFile = std::string::npos; @@ -3409,7 +3409,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 +3441,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,13 +3502,12 @@ 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) { - cacheSize = cacheSize.substr(0, pos); + cacheSize.resize(pos); } this->Features.L1CacheSize += atoi(cacheSize.c_str()); } @@ -3584,8 +3583,7 @@ bool SystemInformationImplementation::QueryProcessor() /** Get total system RAM in units of KiB. */ -SystemInformation::LongLong -SystemInformationImplementation::GetHostMemoryTotal() +long long SystemInformationImplementation::GetHostMemoryTotal() { #if defined(_WIN32) # if defined(_MSC_VER) && _MSC_VER < 1300 @@ -3600,7 +3598,7 @@ SystemInformationImplementation::GetHostMemoryTotal() return statex.ullTotalPhys / 1024; # endif #elif defined(__linux) - SystemInformation::LongLong memTotal = 0; + long long memTotal = 0; int ierr = GetFieldFromFile("/proc/meminfo", "MemTotal:", memTotal); if (ierr) { return -1; @@ -3623,11 +3621,10 @@ SystemInformationImplementation::GetHostMemoryTotal() Get total system RAM in units of KiB. This may differ from the host total if a host-wide resource limit is applied. */ -SystemInformation::LongLong -SystemInformationImplementation::GetHostMemoryAvailable( +long long SystemInformationImplementation::GetHostMemoryAvailable( const char* hostLimitEnvVarName) { - SystemInformation::LongLong memTotal = this->GetHostMemoryTotal(); + long long memTotal = this->GetHostMemoryTotal(); // the following mechanism is provided for systems that // apply resource limits across groups of processes. @@ -3638,8 +3635,7 @@ SystemInformationImplementation::GetHostMemoryAvailable( if (hostLimitEnvVarName) { const char* hostLimitEnvVarValue = getenv(hostLimitEnvVarName); if (hostLimitEnvVarValue) { - SystemInformation::LongLong hostLimit = - atoLongLong(hostLimitEnvVarValue); + long long hostLimit = std::atoll(hostLimitEnvVarValue); if (hostLimit > 0) { memTotal = min(hostLimit, memTotal); } @@ -3653,20 +3649,17 @@ SystemInformationImplementation::GetHostMemoryAvailable( Get total system RAM in units of KiB. This may differ from the host total if a per-process resource limit is applied. */ -SystemInformation::LongLong -SystemInformationImplementation::GetProcMemoryAvailable( +long long SystemInformationImplementation::GetProcMemoryAvailable( const char* hostLimitEnvVarName, const char* procLimitEnvVarName) { - SystemInformation::LongLong memAvail = - this->GetHostMemoryAvailable(hostLimitEnvVarName); + long long memAvail = this->GetHostMemoryAvailable(hostLimitEnvVarName); // the following mechanism is provide for systems where rlimits // are not employed. Units are in KiB. if (procLimitEnvVarName) { const char* procLimitEnvVarValue = getenv(procLimitEnvVarName); if (procLimitEnvVarValue) { - SystemInformation::LongLong procLimit = - atoLongLong(procLimitEnvVarValue); + long long procLimit = std::atoll(procLimitEnvVarValue); if (procLimit > 0) { memAvail = min(procLimit, memAvail); } @@ -3678,28 +3671,24 @@ SystemInformationImplementation::GetProcMemoryAvailable( ResourceLimitType rlim; ierr = GetResourceLimit(RLIMIT_DATA, &rlim); if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); + memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); } ierr = GetResourceLimit(RLIMIT_AS, &rlim); if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); + memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); } #elif defined(__APPLE__) struct rlimit rlim; int ierr; ierr = getrlimit(RLIMIT_DATA, &rlim); if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); + memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); } ierr = getrlimit(RLIMIT_RSS, &rlim); if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); + memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); } #endif @@ -3709,8 +3698,7 @@ SystemInformationImplementation::GetProcMemoryAvailable( /** Get RAM used by all processes in the host, in units of KiB. */ -SystemInformation::LongLong -SystemInformationImplementation::GetHostMemoryUsed() +long long SystemInformationImplementation::GetHostMemoryUsed() { #if defined(_WIN32) # if defined(_MSC_VER) && _MSC_VER < 1300 @@ -3727,39 +3715,38 @@ SystemInformationImplementation::GetHostMemoryUsed() #elif defined(__linux) // First try to use MemAvailable, but it only works on newer kernels const char* names2[3] = { "MemTotal:", "MemAvailable:", nullptr }; - SystemInformation::LongLong values2[2] = { SystemInformation::LongLong(0) }; + long long values2[2] = { 0 }; int ierr = GetFieldsFromFile("/proc/meminfo", names2, values2); if (ierr) { const char* names4[5] = { "MemTotal:", "MemFree:", "Buffers:", "Cached:", nullptr }; - SystemInformation::LongLong values4[4] = { SystemInformation::LongLong( - 0) }; + long long values4[4] = { 0 }; ierr = GetFieldsFromFile("/proc/meminfo", names4, values4); if (ierr) { return ierr; } - SystemInformation::LongLong& memTotal = values4[0]; - SystemInformation::LongLong& memFree = values4[1]; - SystemInformation::LongLong& memBuffers = values4[2]; - SystemInformation::LongLong& memCached = values4[3]; + long long& memTotal = values4[0]; + long long& memFree = values4[1]; + long long& memBuffers = values4[2]; + long long& memCached = values4[3]; return memTotal - memFree - memBuffers - memCached; } - SystemInformation::LongLong& memTotal = values2[0]; - SystemInformation::LongLong& memAvail = values2[1]; + long long& memTotal = values2[0]; + long long& memAvail = values2[1]; return memTotal - memAvail; #elif defined(__APPLE__) - SystemInformation::LongLong psz = getpagesize(); + long long psz = getpagesize(); if (psz < 1) { return -1; } const char* names[3] = { "Pages wired down:", "Pages active:", nullptr }; - SystemInformation::LongLong values[2] = { SystemInformation::LongLong(0) }; + long long values[2] = { 0 }; int ierr = GetFieldsFromCommand("vm_stat", names, values); if (ierr) { return -1; } - SystemInformation::LongLong& vmWired = values[0]; - SystemInformation::LongLong& vmActive = values[1]; + long long& vmWired = values[0]; + long long& vmActive = values[1]; return ((vmActive + vmWired) * psz) / 1024; #else return 0; @@ -3770,8 +3757,7 @@ SystemInformationImplementation::GetHostMemoryUsed() Get system RAM used by the process associated with the given process id in units of KiB. */ -SystemInformation::LongLong -SystemInformationImplementation::GetProcMemoryUsed() +long long SystemInformationImplementation::GetProcMemoryUsed() { #if defined(_WIN32) && defined(KWSYS_SYS_HAS_PSAPI) long pid = GetCurrentProcessId(); @@ -3788,14 +3774,14 @@ SystemInformationImplementation::GetProcMemoryUsed() } return pmc.WorkingSetSize / 1024; #elif defined(__linux) - SystemInformation::LongLong memUsed = 0; + long long memUsed = 0; int ierr = GetFieldFromFile("/proc/self/status", "VmRSS:", memUsed); if (ierr) { return -1; } return memUsed; #elif defined(__APPLE__) - SystemInformation::LongLong memUsed = 0; + long long memUsed = 0; pid_t pid = getpid(); std::ostringstream oss; oss << "ps -o rss= -p " << pid; @@ -3859,7 +3845,7 @@ double SystemInformationImplementation::GetLoadAverage() /** Get the process id of the running process. */ -SystemInformation::LongLong SystemInformationImplementation::GetProcessId() +long long SystemInformationImplementation::GetProcessId() { #if defined(_WIN32) return GetCurrentProcessId(); @@ -3893,7 +3879,7 @@ std::string SystemInformationImplementation::GetProgramStack(int firstFrame, int wholePath) { std::ostringstream oss; - std::string programStack = ""; + std::string programStack; #ifdef KWSYS_SYSTEMINFORMATION_HAS_DBGHELP (void)wholePath; @@ -4249,39 +4235,44 @@ 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; } /** Get Cycle differences */ -SystemInformation::LongLong -SystemInformationImplementation::GetCyclesDifference(DELAY_FUNC DelayFunction, - unsigned int uiParameter) +long long SystemInformationImplementation::GetCyclesDifference( + DELAY_FUNC DelayFunction, unsigned int uiParameter) { #if defined(_MSC_VER) && (_MSC_VER >= 1400) unsigned __int64 stamp1, stamp2; +# ifdef _M_ARM64 + stamp1 = _ReadStatusReg(ARM64_PMCCNTR_EL0); + DelayFunction(uiParameter); + stamp2 = _ReadStatusReg(ARM64_PMCCNTR_EL0); +# else stamp1 = __rdtsc(); DelayFunction(uiParameter); stamp2 = __rdtsc(); +# endif return stamp2 - stamp1; #elif USE_ASM_INSTRUCTIONS @@ -4350,7 +4341,7 @@ void SystemInformationImplementation::DelayOverhead(unsigned int uiMS) } /** Works only for windows */ -bool SystemInformationImplementation::IsSMTSupported() +bool SystemInformationImplementation::IsSMTSupported() const { return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical > 1; } @@ -4399,12 +4390,12 @@ void SystemInformationImplementation::CPUCountWindows() DWORD Length = 0; DWORD rc = pGetLogicalProcessorInformation(nullptr, &Length); assert(FALSE == rc); - (void)rc; // Silence unused variable warning in Borland C++ 5.81 + (void)rc; // Silence unused variable warning assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER); ProcInfo.resize(Length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); rc = pGetLogicalProcessorInformation(&ProcInfo[0], &Length); assert(rc != FALSE); - (void)rc; // Silence unused variable warning in Borland C++ 5.81 + (void)rc; // Silence unused variable warning } typedef std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION>::iterator @@ -4432,13 +4423,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; } @@ -4638,7 +4629,7 @@ std::string SystemInformationImplementation::ExtractValueFromSysCtl( size_t pos = this->SysCtlBuffer.find(word); if (pos != std::string::npos) { pos = this->SysCtlBuffer.find(": ", pos); - size_t pos2 = this->SysCtlBuffer.find("\n", pos); + size_t pos2 = this->SysCtlBuffer.find('\n', pos); if (pos != std::string::npos && pos2 != std::string::npos) { return this->SysCtlBuffer.substr(pos + 2, pos2 - pos - 2); } @@ -4733,14 +4724,15 @@ std::string SystemInformationImplementation::ParseValueFromKStat( } pos = command.find(' ', pos + 1); } - args_string.push_back(command.substr(start + 1, command.size() - start - 1)); + command.erase(0, start + 1); + args_string.push_back(command); std::vector<const char*> args; 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); @@ -4922,7 +4914,9 @@ bool SystemInformationImplementation::QueryQNXMemory() while (buffer[pos] == ' ') pos++; - this->TotalPhysicalMemory = atoi(buffer.substr(pos, pos2 - pos).c_str()); + buffer.erase(0, pos); + buffer.resize(pos2); + this->TotalPhysicalMemory = atoi(buffer.c_str()); return true; #endif return false; @@ -5447,19 +5441,19 @@ void SystemInformationImplementation::TrimNewline(std::string& output) { // remove \r std::string::size_type pos = 0; - while ((pos = output.find("\r", pos)) != std::string::npos) { + while ((pos = output.find('\r', pos)) != std::string::npos) { output.erase(pos); } // remove \n pos = 0; - while ((pos = output.find("\n", pos)) != std::string::npos) { + while ((pos = output.find('\n', pos)) != std::string::npos) { output.erase(pos); } } /** Return true if the machine is 64 bits */ -bool SystemInformationImplementation::Is64Bits() +bool SystemInformationImplementation::Is64Bits() const { return this->OSIs64Bit; } diff --git a/Source/kwsys/SystemInformation.hxx.in b/Source/kwsys/SystemInformation.hxx.in index fc42e9dc7..c8efd51d0 100644 --- a/Source/kwsys/SystemInformation.hxx.in +++ b/Source/kwsys/SystemInformation.hxx.in @@ -15,13 +15,6 @@ class SystemInformationImplementation; class @KWSYS_NAMESPACE@_EXPORT SystemInformation { -#if @KWSYS_USE_LONG_LONG@ - typedef long long LongLong; -#elif @KWSYS_USE___INT64@ - typedef __int64 LongLong; -#else -# error "No Long Long" -#endif friend class SystemInformationImplementation; SystemInformationImplementation* Implementation; @@ -104,7 +97,7 @@ public: bool DoesCPUSupportCPUID(); // Retrieve id of the current running process - LongLong GetProcessId(); + long long GetProcessId(); // Retrieve memory information in MiB. size_t GetTotalVirtualMemory(); @@ -120,7 +113,7 @@ public: // Retrieve amount of physical memory installed on the system in KiB // units. - LongLong GetHostMemoryTotal(); + long long GetHostMemoryTotal(); // Get total system RAM in units of KiB available colectivley to all // processes in a process group. An example of a process group @@ -128,7 +121,7 @@ public: // parallel. The amount of memory reported may differ from the host // total if a host wide resource limit is applied. Such reource limits // are reported to us via an application specified environment variable. - LongLong GetHostMemoryAvailable(const char* hostLimitEnvVarName = nullptr); + long long GetHostMemoryAvailable(const char* hostLimitEnvVarName = nullptr); // Get total system RAM in units of KiB available to this process. // This may differ from the host available if a per-process resource @@ -136,14 +129,14 @@ public: // system via rlimit API. Resource limits that are not imposed via // rlimit API may be reported to us via an application specified // environment variable. - LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName = nullptr, - const char* procLimitEnvVarName = nullptr); + long long GetProcMemoryAvailable(const char* hostLimitEnvVarName = nullptr, + const char* procLimitEnvVarName = nullptr); // Get the system RAM used by all processes on the host, in units of KiB. - LongLong GetHostMemoryUsed(); + long long GetHostMemoryUsed(); // Get system RAM used by this process id in units of KiB. - LongLong GetProcMemoryUsed(); + long long GetProcMemoryUsed(); // Return the load average of the machine or -0.0 if it cannot // be determined. diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index d27081b8c..25705ea28 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -6,9 +6,7 @@ # define _XOPEN_SOURCE_EXTENDED #endif -#if defined(_WIN32) && \ - (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || \ - defined(__MINGW32__)) +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__MINGW32__)) # define KWSYS_WINDOWS_DIRS #else # if defined(__SUNPRO_CC) @@ -24,6 +22,7 @@ #include KWSYS_HEADER(Encoding.h) #include KWSYS_HEADER(Encoding.hxx) +#include <algorithm> #include <fstream> #include <iostream> #include <set> @@ -49,27 +48,27 @@ # pragma set woff 1375 /* base class destructor not virtual */ #endif -#include <ctype.h> -#include <errno.h> +#include <cctype> +#include <cerrno> #ifdef __QNX__ # include <malloc.h> /* for malloc/free on QNX */ #endif -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <ctime> #if defined(_WIN32) && !defined(_MSC_VER) && defined(__GNUC__) # include <strings.h> /* for strcasecmp */ #endif #ifdef _MSC_VER -# define umask _umask // Note this is still umask on Borland +# define umask _umask #endif // support for realpath call #ifndef _WIN32 -# include <limits.h> +# include <climits> # include <pwd.h> # include <sys/ioctl.h> # include <sys/time.h> @@ -80,7 +79,7 @@ # include <sys/param.h> # include <termios.h> # endif -# include <signal.h> /* sigprocmask */ +# include <csignal> /* sigprocmask */ #endif #ifdef __linux @@ -123,9 +122,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 @@ -153,9 +152,7 @@ public: } #endif -#if defined(_WIN32) && \ - (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || \ - defined(__MINGW32__)) +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__MINGW32__)) # include <direct.h> # include <io.h> # define _unlink unlink @@ -169,13 +166,6 @@ public: #else # define KWSYS_SYSTEMTOOLS_MAXPATH 16384 #endif -#if defined(__WATCOMC__) -# include <direct.h> -# define _mkdir mkdir -# define _rmdir rmdir -# define _getcwd getcwd -# define _chdir chdir -#endif #if defined(__BEOS__) && !defined(__ZETA__) # include <be/kernel/OS.h> @@ -221,11 +211,17 @@ static time_t windows_filetime_to_posix_time(const FILETIME& ft) #ifdef KWSYS_WINDOWS_DIRS # include <wctype.h> +# ifdef _MSC_VER +typedef KWSYS_NAMESPACE::SystemTools::mode_t mode_t; +# endif -inline int Mkdir(const std::string& dir) +inline int Mkdir(const std::string& dir, const mode_t* mode) { - return _wmkdir( - KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str()); + int ret = + _wmkdir(KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str()); + if (ret == 0 && mode) + KWSYS_NAMESPACE::SystemTools::SetPermissions(dir, *mode); + return ret; } inline int Rmdir(const std::string& dir) { @@ -252,11 +248,7 @@ inline const char* Getcwd(char* buf, unsigned int len) } inline int Chdir(const std::string& dir) { -# if defined(__BORLANDC__) - return chdir(dir.c_str()); -# else return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str()); -# endif } inline void Realpath(const std::string& path, std::string& resolved_path, std::string* errorMessage = 0) @@ -295,9 +287,9 @@ inline void Realpath(const std::string& path, std::string& resolved_path, # include <fcntl.h> # include <unistd.h> -inline int Mkdir(const std::string& dir) +inline int Mkdir(const std::string& dir, const mode_t* mode) { - return mkdir(dir.c_str(), 00777); + return mkdir(dir.c_str(), mode ? *mode : 00777); } inline int Rmdir(const std::string& dir) { @@ -350,7 +342,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 +360,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 +413,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 +444,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,10 +480,13 @@ 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); }; +// Do NOT initialize. Default initialization to zero is necessary. +static SystemToolsStatic* SystemToolsStatics; + #ifdef _WIN32 std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn) { @@ -566,7 +561,7 @@ std::string SystemToolsStatic::GetActualCaseForPathCached(std::string const& p) { // Check to see if actual case has already been called // for this path, and the result is stored in the PathCaseMap - auto& pcm = SystemTools::Statics->PathCaseMap; + auto& pcm = SystemToolsStatics->PathCaseMap; { auto itr = pcm.find(p); if (itr != pcm.end()) { @@ -613,8 +608,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); } } @@ -624,7 +618,7 @@ const char* SystemToolsStatic::GetEnvBuffered(const char* key) { std::string env; if (SystemTools::GetEnv(key, env)) { - std::string& menv = SystemTools::Statics->EnvMap[key]; + std::string& menv = SystemToolsStatics->EnvMap[key]; if (menv != env) { menv = std::move(env); } @@ -884,8 +878,12 @@ const char* SystemTools::GetExecutableExtension() FILE* SystemTools::Fopen(const std::string& file, const char* mode) { #ifdef _WIN32 + // Remove any 'e', which is supported on UNIX, but not Windows. + std::wstring trimmedMode = Encoding::ToWide(mode); + trimmedMode.erase(std::remove(trimmedMode.begin(), trimmedMode.end(), L'e'), + trimmedMode.end()); return _wfopen(Encoding::ToWindowsExtendedPath(file).c_str(), - Encoding::ToWide(mode).c_str()); + trimmedMode.c_str()); #else return fopen(file.c_str(), mode); #endif @@ -913,29 +911,22 @@ bool SystemTools::MakeDirectory(const std::string& path, const mode_t* mode) std::string::size_type pos = 0; std::string topdir; while ((pos = dir.find('/', pos)) != std::string::npos) { - topdir = dir.substr(0, pos); + // all underlying functions use C strings, so temporarily + // end the string here + dir[pos] = '\0'; - if (Mkdir(topdir) == 0 && mode != nullptr) { - SystemTools::SetPermissions(topdir, *mode); - } + Mkdir(dir, mode); + dir[pos] = '/'; ++pos; } topdir = dir; - if (Mkdir(topdir) != 0) { - // There is a bug in the Borland Run time library which makes MKDIR - // return EACCES when it should return EEXISTS + if (Mkdir(topdir, mode) != 0) { // if it is some other error besides directory exists // then return false - if ((errno != EEXIST) -#ifdef __BORLANDC__ - && (errno != EACCES) -#endif - ) { + if (errno != EEXIST) { return false; } - } else if (mode != nullptr) { - SystemTools::SetPermissions(topdir, *mode); } return true; @@ -1011,38 +1002,40 @@ void SystemToolsStatic::ReplaceString(std::string& source, const char* replace, # define KWSYS_ST_KEY_WOW64_64KEY 0x0100 # endif -static bool SystemToolsParseRegistryKey(const std::string& key, - HKEY& primaryKey, std::string& second, - std::string& valuename) +static bool hasPrefix(const std::string& s, const char* pattern, + std::string::size_type spos) { - std::string primary = key; + size_t plen = strlen(pattern); + if (spos != plen) + return false; + return s.compare(0, plen, pattern) == 0; +} - size_t start = primary.find('\\'); +static bool SystemToolsParseRegistryKey(const std::string& key, + HKEY& primaryKey, std::wstring& second, + std::string* valuename) +{ + size_t start = key.find('\\'); if (start == std::string::npos) { return false; } - size_t valuenamepos = primary.find(';'); - if (valuenamepos != std::string::npos) { - valuename = primary.substr(valuenamepos + 1); + size_t valuenamepos = key.find(';'); + if (valuenamepos != std::string::npos && valuename) { + *valuename = key.substr(valuenamepos + 1); } - second = primary.substr(start + 1, valuenamepos - start - 1); - primary = primary.substr(0, start); + second = Encoding::ToWide(key.substr(start + 1, valuenamepos - start - 1)); - if (primary == "HKEY_CURRENT_USER") { + if (hasPrefix(key, "HKEY_CURRENT_USER", start)) { primaryKey = HKEY_CURRENT_USER; - } - if (primary == "HKEY_CURRENT_CONFIG") { + } else if (hasPrefix(key, "HKEY_CURRENT_CONFIG", start)) { primaryKey = HKEY_CURRENT_CONFIG; - } - if (primary == "HKEY_CLASSES_ROOT") { + } else if (hasPrefix(key, "HKEY_CLASSES_ROOT", start)) { primaryKey = HKEY_CLASSES_ROOT; - } - if (primary == "HKEY_LOCAL_MACHINE") { + } else if (hasPrefix(key, "HKEY_LOCAL_MACHINE", start)) { primaryKey = HKEY_LOCAL_MACHINE; - } - if (primary == "HKEY_USERS") { + } else if (hasPrefix(key, "HKEY_USERS", start)) { primaryKey = HKEY_USERS; } @@ -1074,14 +1067,13 @@ bool SystemTools::GetRegistrySubKeys(const std::string& key, KeyWOW64 view) { HKEY primaryKey = HKEY_CURRENT_USER; - std::string second; - std::string valuename; - if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { + std::wstring second; + if (!SystemToolsParseRegistryKey(key, primaryKey, second, nullptr)) { return false; } HKEY hKey; - if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, + if (RegOpenKeyExW(primaryKey, second.c_str(), 0, SystemToolsMakeRegistryMode(KEY_READ, view), &hKey) != ERROR_SUCCESS) { return false; @@ -1121,14 +1113,14 @@ bool SystemTools::ReadRegistryValue(const std::string& key, std::string& value, { bool valueset = false; HKEY primaryKey = HKEY_CURRENT_USER; - std::string second; + std::wstring second; std::string valuename; - if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { + if (!SystemToolsParseRegistryKey(key, primaryKey, second, &valuename)) { return false; } HKEY hKey; - if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, + if (RegOpenKeyExW(primaryKey, second.c_str(), 0, SystemToolsMakeRegistryMode(KEY_READ, view), &hKey) != ERROR_SUCCESS) { return false; @@ -1175,16 +1167,16 @@ bool SystemTools::WriteRegistryValue(const std::string& key, const std::string& value, KeyWOW64 view) { HKEY primaryKey = HKEY_CURRENT_USER; - std::string second; + std::wstring second; std::string valuename; - if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { + if (!SystemToolsParseRegistryKey(key, primaryKey, second, &valuename)) { return false; } HKEY hKey; DWORD dwDummy; wchar_t lpClass[] = L""; - if (RegCreateKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, lpClass, + if (RegCreateKeyExW(primaryKey, second.c_str(), 0, lpClass, REG_OPTION_NON_VOLATILE, SystemToolsMakeRegistryMode(KEY_WRITE, view), nullptr, &hKey, &dwDummy) != ERROR_SUCCESS) { @@ -1219,14 +1211,14 @@ bool SystemTools::WriteRegistryValue(const std::string&, const std::string&, bool SystemTools::DeleteRegistryValue(const std::string& key, KeyWOW64 view) { HKEY primaryKey = HKEY_CURRENT_USER; - std::string second; + std::wstring second; std::string valuename; - if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { + if (!SystemToolsParseRegistryKey(key, primaryKey, second, &valuename)) { return false; } HKEY hKey; - if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, + if (RegOpenKeyExW(primaryKey, second.c_str(), 0, SystemToolsMakeRegistryMode(KEY_WRITE, view), &hKey) != ERROR_SUCCESS) { return false; @@ -1435,11 +1427,7 @@ int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf) // long paths, but _wstat64 rejects paths with '?' in them, thinking // they are wildcards. std::wstring const& wpath = Encoding::ToWide(path); -# if defined(__BORLANDC__) - return _wstati64(wpath.c_str(), buf); -# else return _wstat64(wpath.c_str(), buf); -# endif #else return stat(path.c_str(), buf); #endif @@ -1448,15 +1436,15 @@ int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf) #ifdef __CYGWIN__ bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path) { - auto itr = SystemTools::Statics->Cyg2Win32Map.find(path); - if (itr != SystemTools::Statics->Cyg2Win32Map.end()) { + auto itr = SystemToolsStatics->Cyg2Win32Map.find(path); + if (itr != SystemToolsStatics->Cyg2Win32Map.end()) { strncpy(win32_path, itr->second.c_str(), MAX_PATH); } else { if (cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, win32_path, MAX_PATH) != 0) { win32_path[0] = 0; } - SystemTools::Statics->Cyg2Win32Map.insert( + SystemToolsStatics->Cyg2Win32Map.insert( SystemToolsStatic::StringMap::value_type(path, win32_path)); } return win32_path[0] != 0; @@ -1858,7 +1846,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; } @@ -1867,7 +1855,7 @@ std::string SystemTools::CropString(const std::string& s, size_t max_len) size_t middle = max_len / 2; - n += s.substr(0, middle); + n.assign(s, 0, middle); n += s.substr(s.size() - (max_len - middle)); if (max_len > 2) { @@ -1893,10 +1881,10 @@ 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); + std::string::size_type pos2 = path.find(sep, pos1); while (pos2 != std::string::npos) { paths.push_back(path.substr(pos1, pos2 - pos1)); pos1 = pos2 + 1; @@ -2065,8 +2053,10 @@ void SystemTools::ConvertToUnixSlashes(std::string& path) #ifdef HAVE_GETPWNAM else if (pathCString[0] == '~') { std::string::size_type idx = path.find_first_of("/\0"); - std::string user = path.substr(1, idx - 1); - passwd* pw = getpwnam(user.c_str()); + char oldch = path[idx]; + path[idx] = '\0'; + passwd* pw = getpwnam(path.c_str() + 1); + path[idx] = oldch; if (pw) { path.replace(0, idx, pw->pw_dir); } @@ -2103,7 +2093,7 @@ std::string SystemTools::ConvertToUnixOutputPath(const std::string& path) ret.erase(pos, 1); } // escape spaces and () in the path - if (ret.find_first_of(" ") != std::string::npos) { + if (ret.find_first_of(' ') != std::string::npos) { std::string result; char lastch = 1; for (const char* ch = ret.c_str(); *ch != '\0'; ++ch) { @@ -2501,8 +2491,8 @@ bool SystemTools::CopyADirectory(const std::string& source, return false; } for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { - if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") && - strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..")) { + if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") != 0 && + strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..") != 0) { std::string fullPath = source; fullPath += "/"; fullPath += dir.GetFile(static_cast<unsigned long>(fileNum)); @@ -2664,8 +2654,8 @@ bool SystemTools::RemoveADirectory(const std::string& source) dir.Load(source); size_t fileNum; for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { - if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") && - strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..")) { + if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") != 0 && + strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..") != 0) { std::string fullPath = source; fullPath += "/"; fullPath += dir.GetFile(static_cast<unsigned long>(fileNum)); @@ -2797,7 +2787,7 @@ std::string SystemTools::FindProgram(const std::string& name, for (std::string const& ext : extensions) { tryPath = name; tryPath += ext; - if (SystemTools::FileExists(tryPath, true)) { + if (SystemTools::FileIsExecutable(tryPath)) { return SystemTools::CollapseFullPath(tryPath); } } @@ -2805,7 +2795,7 @@ std::string SystemTools::FindProgram(const std::string& name, #endif // now try just the name - if (SystemTools::FileExists(name, true)) { + if (SystemTools::FileIsExecutable(name)) { return SystemTools::CollapseFullPath(name); } // now construct the path @@ -2835,7 +2825,7 @@ std::string SystemTools::FindProgram(const std::string& name, tryPath = p; tryPath += name; tryPath += ext; - if (SystemTools::FileExists(tryPath, true)) { + if (SystemTools::FileIsExecutable(tryPath)) { return SystemTools::CollapseFullPath(tryPath); } } @@ -2843,7 +2833,7 @@ std::string SystemTools::FindProgram(const std::string& name, // now try it without them tryPath = p; tryPath += name; - if (SystemTools::FileExists(tryPath, true)) { + if (SystemTools::FileIsExecutable(tryPath)) { return SystemTools::CollapseFullPath(tryPath); } } @@ -2998,6 +2988,15 @@ bool SystemTools::FileIsDirectory(const std::string& inName) } } +bool SystemTools::FileIsExecutable(const std::string& name) +{ +#if defined(_WIN32) + return SystemTools::FileExists(name, true); +#else + return !FileIsDirectory(name) && TestFileAccess(name, TEST_FILE_EXECUTE); +#endif +} + bool SystemTools::FileIsSymlink(const std::string& name) { #if defined(_WIN32) @@ -3107,16 +3106,14 @@ int SystemTools::ChangeDirectory(const std::string& dir) return Chdir(dir); } -std::string SystemTools::GetCurrentWorkingDirectory(bool collapse) +std::string SystemTools::GetCurrentWorkingDirectory() { char buf[2048]; const char* cwd = Getcwd(buf, 2048); std::string path; if (cwd) { path = cwd; - } - if (collapse) { - return SystemTools::CollapseFullPath(path); + SystemTools::ConvertToUnixSlashes(path); } return path; } @@ -3132,17 +3129,17 @@ bool SystemTools::SplitProgramPath(const std::string& in_name, std::string& dir, std::string& file, bool) { dir = in_name; - file = ""; + file.clear(); SystemTools::ConvertToUnixSlashes(dir); if (!SystemTools::FileIsDirectory(dir)) { - std::string::size_type slashPos = dir.rfind("/"); + std::string::size_type slashPos = dir.rfind('/'); if (slashPos != std::string::npos) { file = dir.substr(slashPos + 1); - dir = dir.substr(0, slashPos); + dir.resize(slashPos); } else { file = dir; - dir = ""; + dir.clear(); } } if (!(dir.empty()) && !SystemTools::FileIsDirectory(dir)) { @@ -3164,7 +3161,7 @@ bool SystemTools::FindProgramPath(const char* argv0, std::string& pathOut, failures.push_back(self); SystemTools::ConvertToUnixSlashes(self); self = SystemTools::FindProgram(self); - if (!SystemTools::FileExists(self)) { + if (!SystemTools::FileIsExecutable(self)) { if (buildDir) { std::string intdir = "."; #ifdef CMAKE_INTDIR @@ -3179,14 +3176,14 @@ bool SystemTools::FindProgramPath(const char* argv0, std::string& pathOut, } } if (installPrefix) { - if (!SystemTools::FileExists(self)) { + if (!SystemTools::FileIsExecutable(self)) { failures.push_back(self); self = installPrefix; self += "/bin/"; self += exeName; } } - if (!SystemTools::FileExists(self)) { + if (!SystemTools::FileIsExecutable(self)) { failures.push_back(self); std::ostringstream msg; msg << "Can not find the command line program "; @@ -3208,11 +3205,6 @@ bool SystemTools::FindProgramPath(const char* argv0, std::string& pathOut, return true; } -std::string SystemTools::CollapseFullPath(const std::string& in_relative) -{ - return SystemTools::CollapseFullPath(in_relative, nullptr); -} - #if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP void SystemTools::AddTranslationPath(const std::string& a, const std::string& b) @@ -3237,7 +3229,7 @@ void SystemTools::AddTranslationPath(const std::string& a, path_b += '/'; } if (!(path_a == path_b)) { - SystemTools::Statics->TranslationMap.insert( + SystemToolsStatics->TranslationMap.insert( SystemToolsStatic::StringMap::value_type(std::move(path_a), std::move(path_b))); } @@ -3267,9 +3259,9 @@ void SystemTools::CheckTranslationPath(std::string& path) // In case a file was specified we still have to go through this: // Now convert any path found in the table back to the one desired: - for (auto const& pair : SystemTools::Statics->TranslationMap) { + for (auto const& pair : SystemToolsStatics->TranslationMap) { // We need to check of the path is a substring of the other path - if (path.find(pair.first) == 0) { + if (path.compare(0, pair.first.size(), pair.first) == 0) { path = path.replace(0, pair.first.size(), pair.second); } } @@ -3302,25 +3294,10 @@ static void SystemToolsAppendComponents( } } -std::string SystemTools::CollapseFullPath(const std::string& in_path, - const char* in_base) -{ - // Use the current working directory as a base path. - char buf[2048]; - const char* res_in_base = in_base; - if (!res_in_base) { - if (const char* cwd = Getcwd(buf, 2048)) { - res_in_base = cwd; - } else { - res_in_base = ""; - } - } +namespace { - return SystemTools::CollapseFullPath(in_path, std::string(res_in_base)); -} - -std::string SystemTools::CollapseFullPath(const std::string& in_path, - const std::string& in_base) +std::string CollapseFullPathImpl(std::string const& in_path, + std::string const* in_base) { // Collect the output path components. std::vector<std::string> out_components; @@ -3333,8 +3310,15 @@ std::string SystemTools::CollapseFullPath(const std::string& in_path, // If the input path is relative, start with a base path. if (path_components[0].empty()) { std::vector<std::string> base_components; - // Use the given base path. - SystemTools::SplitPath(in_base, base_components); + + if (in_base) { + // Use the given base path. + SystemTools::SplitPath(*in_base, base_components); + } else { + // Use the current working directory as a base path. + std::string cwd = SystemTools::GetCurrentWorkingDirectory(); + SystemTools::SplitPath(cwd, base_components); + } // Append base path components to the output path. out_components.push_back(base_components[0]); @@ -3367,12 +3351,34 @@ std::string SystemTools::CollapseFullPath(const std::string& in_path, SystemTools::CheckTranslationPath(newPath); #endif #ifdef _WIN32 - newPath = SystemTools::Statics->GetActualCaseForPathCached(newPath); + newPath = SystemToolsStatics->GetActualCaseForPathCached(newPath); SystemTools::ConvertToUnixSlashes(newPath); #endif // Return the reconstructed path. return newPath; } +} + +std::string SystemTools::CollapseFullPath(std::string const& in_path) +{ + return CollapseFullPathImpl(in_path, nullptr); +} + +std::string SystemTools::CollapseFullPath(std::string const& in_path, + const char* in_base) +{ + if (!in_base) { + return CollapseFullPathImpl(in_path, nullptr); + } + std::string tmp_base = in_base; + return CollapseFullPathImpl(in_path, &tmp_base); +} + +std::string SystemTools::CollapseFullPath(std::string const& in_path, + std::string const& in_base) +{ + return CollapseFullPathImpl(in_path, &in_base); +} // compute the relative path from here to there std::string SystemTools::RelativePath(const std::string& local, @@ -3541,7 +3547,7 @@ void SystemTools::SplitPath(const std::string& p, // Expand home directory references if requested. if (expand_home_dir && !root.empty() && root[0] == '~') { std::string homedir; - root = root.substr(0, root.size() - 1); + root.resize(root.size() - 1); if (root.size() == 1) { #if defined(_WIN32) && !defined(__CYGWIN__) if (!SystemTools::GetEnv("USERPROFILE", homedir)) @@ -3571,14 +3577,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); } } @@ -3594,7 +3600,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); @@ -3685,19 +3691,20 @@ std::string SystemTools::GetFilenamePath(const std::string& filename) std::string fn = filename; SystemTools::ConvertToUnixSlashes(fn); - std::string::size_type slash_pos = fn.rfind("/"); - if (slash_pos != std::string::npos) { - std::string ret = fn.substr(0, slash_pos); - if (ret.size() == 2 && ret[1] == ':') { - return ret + '/'; - } - if (ret.empty()) { - return "/"; - } - return ret; - } else { + std::string::size_type slash_pos = fn.rfind('/'); + if (slash_pos == 0) { + return "/"; + } + if (slash_pos == 2 && fn[1] == ':') { + // keep the / after a drive letter + fn.resize(3); + return fn; + } + if (slash_pos == std::string::npos) { return ""; } + fn.resize(slash_pos); + return fn; } /** @@ -3727,7 +3734,8 @@ std::string SystemTools::GetFilenameExtension(const std::string& filename) std::string name = SystemTools::GetFilenameName(filename); std::string::size_type dot_pos = name.find('.'); if (dot_pos != std::string::npos) { - return name.substr(dot_pos); + name.erase(0, dot_pos); + return name; } else { return ""; } @@ -3742,7 +3750,8 @@ std::string SystemTools::GetFilenameLastExtension(const std::string& filename) std::string name = SystemTools::GetFilenameName(filename); std::string::size_type dot_pos = name.rfind('.'); if (dot_pos != std::string::npos) { - return name.substr(dot_pos); + name.erase(0, dot_pos); + return name; } else { return ""; } @@ -3758,10 +3767,9 @@ std::string SystemTools::GetFilenameWithoutExtension( std::string name = SystemTools::GetFilenameName(filename); std::string::size_type dot_pos = name.find('.'); if (dot_pos != std::string::npos) { - return name.substr(0, dot_pos); - } else { - return name; + name.resize(dot_pos); } + return name; } /** @@ -3775,10 +3783,9 @@ std::string SystemTools::GetFilenameWithoutLastExtension( std::string name = SystemTools::GetFilenameName(filename); std::string::size_type dot_pos = name.rfind('.'); if (dot_pos != std::string::npos) { - return name.substr(0, dot_pos); - } else { - return name; + name.resize(dot_pos); } + return name; } bool SystemTools::FileHasSignature(const char* filename, const char* signature, @@ -3828,7 +3835,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) { @@ -4000,7 +4007,8 @@ bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath) // if the path passed in has quotes around it, first remove the quotes if (!path.empty() && path[0] == '"' && path.back() == '"') { - tempPath = path.substr(1, path.length() - 2); + tempPath.resize(path.length() - 1); + tempPath.erase(0, 1); } std::wstring wtempPath = Encoding::ToWide(tempPath); @@ -4219,8 +4227,8 @@ bool SystemTools::IsSubDirectory(const std::string& cSubdir, if (subdir[expectedSlashPosition] != '/') { return false; } - std::string s = subdir.substr(0, dir.size()); - return SystemTools::ComparePath(s, dir); + subdir.resize(dir.size()); + return SystemTools::ComparePath(subdir, dir); } void SystemTools::Delay(unsigned int msec) @@ -4516,7 +4524,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 @@ -4529,13 +4537,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)) @@ -4559,13 +4571,37 @@ 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; } -// These must NOT be initialized. Default initialization to zero is -// necessary. +// ---------------------------------------------------------------------- +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))) { + char bytes[] = { url[i + 1], url[i + 2], '\0' }; + ret += static_cast<char>(strtoul(bytes, nullptr, 16)); + i += 2; + } else { + ret += url[i]; + } + } + return ret; +} + +// ---------------------------------------------------------------------- +// Do NOT initialize. Default initialization to zero is necessary. static unsigned int SystemToolsManagerCount; -SystemToolsStatic* SystemTools::Statics; // SystemToolsManager manages the SystemTools singleton. // SystemToolsManager should be included in any translation unit @@ -4608,7 +4644,7 @@ void SystemTools::ClassInitialize() #endif // Create statics singleton instance - SystemTools::Statics = new SystemToolsStatic; + SystemToolsStatics = new SystemToolsStatic; #if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP // Add some special translation paths for unix. These are not added @@ -4658,7 +4694,7 @@ void SystemTools::ClassInitialize() void SystemTools::ClassFinalize() { - delete SystemTools::Statics; + delete SystemToolsStatics; } } // namespace KWSYS_NAMESPACE diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index c4ab9d4f3..5dbb726a0 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -67,7 +67,7 @@ static SystemToolsManager SystemToolsManagerInstance; // combined using the | operator. typedef int TestFilePermissions; #if defined(_WIN32) && !defined(__CYGWIN__) -// On Windows (VC and Borland), no system header defines these constants... +// On Windows (VC), no system header defines these constants... static const TestFilePermissions TEST_FILE_OK = 0; static const TestFilePermissions TEST_FILE_READ = 4; static const TestFilePermissions TEST_FILE_WRITE = 2; @@ -317,11 +317,7 @@ public: * Cross platform wrapper for stat struct */ #if defined(_WIN32) && !defined(__CYGWIN__) -# if defined(__BORLANDC__) - typedef struct stati64 Stat_t; -# else typedef struct _stat64 Stat_t; -# endif #else typedef struct stat Stat_t; #endif @@ -411,11 +407,11 @@ public: * (which defaults to the current working directory). The full path * is returned. */ - static std::string CollapseFullPath(const std::string& in_relative); - static std::string CollapseFullPath(const std::string& in_relative, + static std::string CollapseFullPath(std::string const& in_path); + static std::string CollapseFullPath(std::string const& in_path, const char* in_base); - static std::string CollapseFullPath(const std::string& in_relative, - const std::string& in_base); + static std::string CollapseFullPath(std::string const& in_path, + std::string const& in_base); /** * Get the real path for a given path, removing all symlinks. In @@ -549,12 +545,13 @@ public: */ /** - * Open a file considering unicode. + * Open a file considering unicode. On Windows, if 'e' is present in + * mode it is first discarded. */ static FILE* Fopen(const std::string& file, const char* mode); /** - * Visual C++ does not define mode_t (note that Borland does, however). + * Visual C++ does not define mode_t. */ #if defined(_MSC_VER) typedef unsigned short mode_t; @@ -677,6 +674,11 @@ public: static bool FileIsDirectory(const std::string& name); /** + * Return true if the file is an executable + */ + static bool FileIsExecutable(const std::string& name); + + /** * Return true if the file is a symlink */ static bool FileIsSymlink(const std::string& name); @@ -869,7 +871,7 @@ public: /** * Get current working directory CWD */ - static std::string GetCurrentWorkingDirectory(bool collapse = true); + static std::string GetCurrentWorkingDirectory(); /** * Change directory to the directory specified @@ -935,22 +937,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: /** @@ -971,7 +983,6 @@ private: return &SystemToolsManagerInstance; } - static SystemToolsStatic* Statics; friend class SystemToolsStatic; friend class SystemToolsManager; }; diff --git a/Source/kwsys/hash_fun.hxx.in b/Source/kwsys/hash_fun.hxx.in deleted file mode 100644 index 8626c2aa2..000000000 --- a/Source/kwsys/hash_fun.hxx.in +++ /dev/null @@ -1,166 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -/* - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef @KWSYS_NAMESPACE@_hash_fun_hxx -#define @KWSYS_NAMESPACE@_hash_fun_hxx - -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include <stddef.h> // size_t -#include <string> - -namespace @KWSYS_NAMESPACE@ { - -template <class _Key> -struct hash -{ -}; - -inline size_t _stl_hash_string(const char* __s) -{ - unsigned long __h = 0; - for (; *__s; ++__s) - __h = 5 * __h + *__s; - - return size_t(__h); -} - -template <> -struct hash<char*> -{ - size_t operator()(const char* __s) const { return _stl_hash_string(__s); } -}; - -template <> -struct hash<const char*> -{ - size_t operator()(const char* __s) const { return _stl_hash_string(__s); } -}; - -template <> -struct hash<std::string> -{ - size_t operator()(const std::string& __s) const - { - return _stl_hash_string(__s.c_str()); - } -}; - -#if !defined(__BORLANDC__) -template <> -struct hash<const std::string> -{ - size_t operator()(const std::string& __s) const - { - return _stl_hash_string(__s.c_str()); - } -}; -#endif - -template <> -struct hash<char> -{ - size_t operator()(char __x) const { return __x; } -}; - -template <> -struct hash<unsigned char> -{ - size_t operator()(unsigned char __x) const { return __x; } -}; - -template <> -struct hash<signed char> -{ - size_t operator()(unsigned char __x) const { return __x; } -}; - -template <> -struct hash<short> -{ - size_t operator()(short __x) const { return __x; } -}; - -template <> -struct hash<unsigned short> -{ - size_t operator()(unsigned short __x) const { return __x; } -}; - -template <> -struct hash<int> -{ - size_t operator()(int __x) const { return __x; } -}; - -template <> -struct hash<unsigned int> -{ - size_t operator()(unsigned int __x) const { return __x; } -}; - -template <> -struct hash<long> -{ - size_t operator()(long __x) const { return __x; } -}; - -template <> -struct hash<unsigned long> -{ - size_t operator()(unsigned long __x) const { return __x; } -}; - -// use long long or __int64 -#if @KWSYS_USE_LONG_LONG@ -template <> -struct hash<long long> -{ - size_t operator()(long long __x) const { return __x; } -}; - -template <> -struct hash<unsigned long long> -{ - size_t operator()(unsigned long long __x) const { return __x; } -}; -#elif @KWSYS_USE___INT64@ -template <> -struct hash<__int64> -{ - size_t operator()(__int64 __x) const { return __x; } -}; -template <> -struct hash<unsigned __int64> -{ - size_t operator()(unsigned __int64 __x) const { return __x; } -}; -#endif // use long long or __int64 - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/Source/kwsys/hash_map.hxx.in b/Source/kwsys/hash_map.hxx.in deleted file mode 100644 index 5f04e9c16..000000000 --- a/Source/kwsys/hash_map.hxx.in +++ /dev/null @@ -1,423 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -/* - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef @KWSYS_NAMESPACE@_hash_map_hxx -#define @KWSYS_NAMESPACE@_hash_map_hxx - -#include <@KWSYS_NAMESPACE@/hashtable.hxx> - -#include <@KWSYS_NAMESPACE@/hash_fun.hxx> - -#include <functional> // equal_to - -#if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4284) -# pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -# pragma set woff 1174 -# pragma set woff 1375 -#endif - -namespace @KWSYS_NAMESPACE@ { - -// select1st is an extension: it is not part of the standard. -template <class T1, class T2> -struct hash_select1st -{ - const T1& operator()(const std::pair<T1, T2>& __x) const - { - return __x.first; - } -}; - -// Forward declaration of equality operator; needed for friend declaration. - -template <class _Key, class _Tp, class _HashFcn = hash<_Key>, - class _EqualKey = std::equal_to<_Key>, - class _Alloc = std::allocator<char> > -class hash_map; - -template <class _Key, class _Tp, class _HashFn, class _EqKey, class _Alloc> -bool operator==(const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&, - const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&); - -template <class _Key, class _Tp, class _HashFcn, class _EqualKey, class _Alloc> -class hash_map -{ -private: - typedef hashtable<std::pair<const _Key, _Tp>, _Key, _HashFcn, - hash_select1st<const _Key, _Tp>, _EqualKey, _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef _Tp data_type; - typedef _Tp mapped_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_map() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_map(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_map(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_map(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template <class _InputIterator> - hash_map(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template <class _InputIterator> - hash_map(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template <class _InputIterator> - hash_map(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template <class _InputIterator> - hash_map(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_unique(__f, __l); - } - -public: - size_type size() const { return _M_ht.size(); } - size_type max_size() const { return _M_ht.max_size(); } - bool empty() const { return _M_ht.empty(); } - void swap(hash_map& __hs) { _M_ht.swap(__hs._M_ht); } - - friend bool operator==<>(const hash_map&, const hash_map&); - - iterator begin() { return _M_ht.begin(); } - iterator end() { return _M_ht.end(); } - const_iterator begin() const { return _M_ht.begin(); } - const_iterator end() const { return _M_ht.end(); } - -public: - std::pair<iterator, bool> insert(const value_type& __obj) - { - return _M_ht.insert_unique(__obj); - } - template <class _InputIterator> - void insert(_InputIterator __f, _InputIterator __l) - { - _M_ht.insert_unique(__f, __l); - } - std::pair<iterator, bool> insert_noresize(const value_type& __obj) - { - return _M_ht.insert_unique_noresize(__obj); - } - - iterator find(const key_type& __key) { return _M_ht.find(__key); } - const_iterator find(const key_type& __key) const - { - return _M_ht.find(__key); - } - - _Tp& operator[](const key_type& __key) - { - return _M_ht.find_or_insert(value_type(__key, _Tp())).second; - } - - size_type count(const key_type& __key) const { return _M_ht.count(__key); } - - std::pair<iterator, iterator> equal_range(const key_type& __key) - { - return _M_ht.equal_range(__key); - } - std::pair<const_iterator, const_iterator> equal_range( - const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc> -bool operator==(const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - return __hm1._M_ht == __hm2._M_ht; -} - -template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc> -inline bool operator!=( - const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - return !(__hm1 == __hm2); -} - -template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc> -inline void swap(hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - __hm1.swap(__hm2); -} - -// Forward declaration of equality operator; needed for friend declaration. - -template <class _Key, class _Tp, class _HashFcn = hash<_Key>, - class _EqualKey = std::equal_to<_Key>, - class _Alloc = std::allocator<char> > -class hash_multimap; - -template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc> -bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2); - -template <class _Key, class _Tp, class _HashFcn, class _EqualKey, class _Alloc> -class hash_multimap -{ -private: - typedef hashtable<std::pair<const _Key, _Tp>, _Key, _HashFcn, - hash_select1st<const _Key, _Tp>, _EqualKey, _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef _Tp data_type; - typedef _Tp mapped_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_multimap() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_multimap(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_multimap(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_multimap(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template <class _InputIterator> - hash_multimap(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template <class _InputIterator> - hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template <class _InputIterator> - hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template <class _InputIterator> - hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_equal(__f, __l); - } - -public: - size_type size() const { return _M_ht.size(); } - size_type max_size() const { return _M_ht.max_size(); } - bool empty() const { return _M_ht.empty(); } - void swap(hash_multimap& __hs) { _M_ht.swap(__hs._M_ht); } - - friend bool operator==<>(const hash_multimap&, const hash_multimap&); - - iterator begin() { return _M_ht.begin(); } - iterator end() { return _M_ht.end(); } - const_iterator begin() const { return _M_ht.begin(); } - const_iterator end() const { return _M_ht.end(); } - -public: - iterator insert(const value_type& __obj) - { - return _M_ht.insert_equal(__obj); - } - template <class _InputIterator> - void insert(_InputIterator __f, _InputIterator __l) - { - _M_ht.insert_equal(__f, __l); - } - iterator insert_noresize(const value_type& __obj) - { - return _M_ht.insert_equal_noresize(__obj); - } - - iterator find(const key_type& __key) { return _M_ht.find(__key); } - const_iterator find(const key_type& __key) const - { - return _M_ht.find(__key); - } - - size_type count(const key_type& __key) const { return _M_ht.count(__key); } - - std::pair<iterator, iterator> equal_range(const key_type& __key) - { - return _M_ht.equal_range(__key); - } - std::pair<const_iterator, const_iterator> equal_range( - const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - -public: - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc> -bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2) -{ - return __hm1._M_ht == __hm2._M_ht; -} - -template <class _Key, class _Tp, class _HF, class _EqKey, class _Alloc> -inline bool operator!=( - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2) -{ - return !(__hm1 == __hm2); -} - -template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc> -inline void swap(hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - __hm1.swap(__hm2); -} - -} // namespace @KWSYS_NAMESPACE@ - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -# pragma reset woff 1174 -# pragma reset woff 1375 -#endif - -#if defined(_MSC_VER) -# pragma warning(pop) -#endif - -#endif diff --git a/Source/kwsys/hash_set.hxx.in b/Source/kwsys/hash_set.hxx.in deleted file mode 100644 index f4a37eebd..000000000 --- a/Source/kwsys/hash_set.hxx.in +++ /dev/null @@ -1,392 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -/* - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef @KWSYS_NAMESPACE@_hash_set_hxx -#define @KWSYS_NAMESPACE@_hash_set_hxx - -#include <@KWSYS_NAMESPACE@/hashtable.hxx> - -#include <@KWSYS_NAMESPACE@/hash_fun.hxx> - -#include <functional> // equal_to - -#if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4284) -# pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -# pragma set woff 1174 -# pragma set woff 1375 -#endif - -namespace @KWSYS_NAMESPACE@ { - -// identity is an extension: it is not part of the standard. -template <class _Tp> -struct _Identity -{ - const _Tp& operator()(const _Tp& __x) const { return __x; } -}; - -// Forward declaration of equality operator; needed for friend declaration. - -template <class _Value, class _HashFcn = hash<_Value>, - class _EqualKey = std::equal_to<_Value>, - class _Alloc = std::allocator<char> > -class hash_set; - -template <class _Value, class _HashFcn, class _EqualKey, class _Alloc> -bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2); - -template <class _Value, class _HashFcn, class _EqualKey, class _Alloc> -class hash_set -{ -private: - typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey, - _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::const_pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::const_reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::const_iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_set() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_set(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_set(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_set(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template <class _InputIterator> - hash_set(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template <class _InputIterator> - hash_set(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template <class _InputIterator> - hash_set(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template <class _InputIterator> - hash_set(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_unique(__f, __l); - } - -public: - size_type size() const { return _M_ht.size(); } - size_type max_size() const { return _M_ht.max_size(); } - bool empty() const { return _M_ht.empty(); } - void swap(hash_set& __hs) { _M_ht.swap(__hs._M_ht); } - - friend bool operator==<>(const hash_set&, const hash_set&); - - iterator begin() const { return _M_ht.begin(); } - iterator end() const { return _M_ht.end(); } - -public: - std::pair<iterator, bool> insert(const value_type& __obj) - { - typedef typename _Ht::iterator _Ht_iterator; - std::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique(__obj); - return std::pair<iterator, bool>(__p.first, __p.second); - } - template <class _InputIterator> - void insert(_InputIterator __f, _InputIterator __l) - { - _M_ht.insert_unique(__f, __l); - } - std::pair<iterator, bool> insert_noresize(const value_type& __obj) - { - typedef typename _Ht::iterator _Ht_iterator; - std::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique_noresize(__obj); - return std::pair<iterator, bool>(__p.first, __p.second); - } - - iterator find(const key_type& __key) const { return _M_ht.find(__key); } - - size_type count(const key_type& __key) const { return _M_ht.count(__key); } - - std::pair<iterator, iterator> equal_range(const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - -public: - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template <class _Value, class _HashFcn, class _EqualKey, class _Alloc> -bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return __hs1._M_ht == __hs2._M_ht; -} - -template <class _Value, class _HashFcn, class _EqualKey, class _Alloc> -inline bool operator!=( - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return !(__hs1 == __hs2); -} - -template <class _Val, class _HashFcn, class _EqualKey, class _Alloc> -inline void swap(hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - __hs1.swap(__hs2); -} - -template <class _Value, class _HashFcn = hash<_Value>, - class _EqualKey = std::equal_to<_Value>, - class _Alloc = std::allocator<char> > -class hash_multiset; - -template <class _Val, class _HashFcn, class _EqualKey, class _Alloc> -bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2); - -template <class _Value, class _HashFcn, class _EqualKey, class _Alloc> -class hash_multiset -{ -private: - typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey, - _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::const_pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::const_reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::const_iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_multiset() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_multiset(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_multiset(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_multiset(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template <class _InputIterator> - hash_multiset(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template <class _InputIterator> - hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template <class _InputIterator> - hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template <class _InputIterator> - hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_equal(__f, __l); - } - -public: - size_type size() const { return _M_ht.size(); } - size_type max_size() const { return _M_ht.max_size(); } - bool empty() const { return _M_ht.empty(); } - void swap(hash_multiset& hs) { _M_ht.swap(hs._M_ht); } - - friend bool operator==<>(const hash_multiset&, const hash_multiset&); - - iterator begin() const { return _M_ht.begin(); } - iterator end() const { return _M_ht.end(); } - -public: - iterator insert(const value_type& __obj) - { - return _M_ht.insert_equal(__obj); - } - template <class _InputIterator> - void insert(_InputIterator __f, _InputIterator __l) - { - _M_ht.insert_equal(__f, __l); - } - iterator insert_noresize(const value_type& __obj) - { - return _M_ht.insert_equal_noresize(__obj); - } - - iterator find(const key_type& __key) const { return _M_ht.find(__key); } - - size_type count(const key_type& __key) const { return _M_ht.count(__key); } - - std::pair<iterator, iterator> equal_range(const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - -public: - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template <class _Val, class _HashFcn, class _EqualKey, class _Alloc> -bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return __hs1._M_ht == __hs2._M_ht; -} - -template <class _Val, class _HashFcn, class _EqualKey, class _Alloc> -inline bool operator!=( - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return !(__hs1 == __hs2); -} - -template <class _Val, class _HashFcn, class _EqualKey, class _Alloc> -inline void swap(hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - __hs1.swap(__hs2); -} - -} // namespace @KWSYS_NAMESPACE@ - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -# pragma reset woff 1174 -# pragma reset woff 1375 -#endif - -#if defined(_MSC_VER) -# pragma warning(pop) -#endif - -#endif diff --git a/Source/kwsys/hashtable.hxx.in b/Source/kwsys/hashtable.hxx.in deleted file mode 100644 index 8c4b0025f..000000000 --- a/Source/kwsys/hashtable.hxx.in +++ /dev/null @@ -1,995 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -/* - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifdef __BORLANDC__ -# pragma warn - 8027 /* 'for' not inlined. */ -# pragma warn - 8026 /* 'exception' not inlined. */ -#endif - -#ifndef @KWSYS_NAMESPACE@_hashtable_hxx -# define @KWSYS_NAMESPACE@_hashtable_hxx - -# include <@KWSYS_NAMESPACE@/Configure.hxx> - -# include <algorithm> // lower_bound -# include <iterator> // iterator_traits -# include <memory> // allocator -# include <stddef.h> // size_t -# include <utility> // pair -# include <vector> // vector - -# if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4284) -# pragma warning(disable : 4786) -# pragma warning(disable : 4512) /* no assignment operator for class */ -# endif -# if defined(__sgi) && !defined(__GNUC__) -# pragma set woff 3970 /* pointer to int conversion */ 3321 3968 -# endif - -// In C++11, clang will warn about using dynamic exception specifications -// as they are deprecated. But as this class is trying to faithfully -// mimic unordered_set and unordered_map, we want to keep the 'throw()' -// decorations below. So we suppress the warning. -# if defined(__clang__) && defined(__has_warning) -# if __has_warning("-Wdeprecated") -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated" -# endif -# endif - -namespace @KWSYS_NAMESPACE@ { - -template <class _Val> -struct _Hashtable_node -{ - _Hashtable_node* _M_next; - _Val _M_val; - void public_method_to_quiet_warning_about_all_methods_private(); - -private: - void operator=(_Hashtable_node<_Val> const&) = delete; -}; - -template <class _Val, class _Key, class _HashFcn, class _ExtractKey, - class _EqualKey, class _Alloc = std::allocator<char> > -class hashtable; - -template <class _Val, class _Key, class _HashFcn, class _ExtractKey, - class _EqualKey, class _Alloc> -struct _Hashtable_iterator; - -template <class _Val, class _Key, class _HashFcn, class _ExtractKey, - class _EqualKey, class _Alloc> -struct _Hashtable_const_iterator; - -template <class _Val, class _Key, class _HashFcn, class _ExtractKey, - class _EqualKey, class _Alloc> -struct _Hashtable_iterator -{ - typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc> - _Hashtable; - typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, - _Alloc> - iterator; - typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc> - const_iterator; - typedef _Hashtable_node<_Val> _Node; - - typedef std::forward_iterator_tag iterator_category; - typedef _Val value_type; - typedef ptrdiff_t difference_type; - typedef size_t size_type; - typedef _Val& reference; - typedef _Val* pointer; - - _Node* _M_cur; - _Hashtable* _M_ht; - - _Hashtable_iterator(_Node* __n, _Hashtable* __tab) - : _M_cur(__n) - , _M_ht(__tab) - { - } - _Hashtable_iterator() {} - reference operator*() const { return _M_cur->_M_val; } - pointer operator->() const { return &(operator*()); } - iterator& operator++(); - iterator operator++(int); - bool operator==(const iterator& __it) const { return _M_cur == __it._M_cur; } - bool operator!=(const iterator& __it) const { return _M_cur != __it._M_cur; } -}; - -template <class _Val, class _Key, class _HashFcn, class _ExtractKey, - class _EqualKey, class _Alloc> -struct _Hashtable_const_iterator -{ - typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc> - _Hashtable; - typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, - _Alloc> - iterator; - typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc> - const_iterator; - typedef _Hashtable_node<_Val> _Node; - - typedef std::forward_iterator_tag iterator_category; - typedef _Val value_type; - typedef ptrdiff_t difference_type; - typedef size_t size_type; - typedef const _Val& reference; - typedef const _Val* pointer; - - const _Node* _M_cur; - const _Hashtable* _M_ht; - - _Hashtable_const_iterator(const _Node* __n, const _Hashtable* __tab) - : _M_cur(__n) - , _M_ht(__tab) - { - } - _Hashtable_const_iterator() {} - _Hashtable_const_iterator(const iterator& __it) - : _M_cur(__it._M_cur) - , _M_ht(__it._M_ht) - { - } - reference operator*() const { return _M_cur->_M_val; } - pointer operator->() const { return &(operator*()); } - const_iterator& operator++(); - const_iterator operator++(int); - bool operator==(const const_iterator& __it) const - { - return _M_cur == __it._M_cur; - } - bool operator!=(const const_iterator& __it) const - { - return _M_cur != __it._M_cur; - } -}; - -// Note: assumes long is at least 32 bits. -enum -{ - _stl_num_primes = 31 -}; - -// create a function with a static local to that function that returns -// the static -static inline const unsigned long* get_stl_prime_list() -{ - - static const unsigned long _stl_prime_list[_stl_num_primes] = { - 5ul, 11ul, 23ul, 53ul, 97ul, - 193ul, 389ul, 769ul, 1543ul, 3079ul, - 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, - 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, - 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, - 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, - 4294967291ul - }; - - return &_stl_prime_list[0]; -} - -static inline size_t _stl_next_prime(size_t __n) -{ - const unsigned long* __first = get_stl_prime_list(); - const unsigned long* __last = get_stl_prime_list() + (int)_stl_num_primes; - const unsigned long* pos = std::lower_bound(__first, __last, __n); - return pos == __last ? *(__last - 1) : *pos; -} - -// Forward declaration of operator==. - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -class hashtable; - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, - const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2); - -// Hashtables handle allocators a bit differently than other containers -// do. If we're using standard-conforming allocators, then a hashtable -// unconditionally has a member variable to hold its allocator, even if -// it so happens that all instances of the allocator type are identical. -// This is because, for hashtables, this extra storage is negligible. -// Additionally, a base class wouldn't serve any other purposes; it -// wouldn't, for example, simplify the exception-handling code. - -template <class _Val, class _Key, class _HashFcn, class _ExtractKey, - class _EqualKey, class _Alloc> -class hashtable -{ -public: - typedef _Key key_type; - typedef _Val value_type; - typedef _HashFcn hasher; - typedef _EqualKey key_equal; - - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef value_type* pointer; - typedef const value_type* const_pointer; - typedef value_type& reference; - typedef const value_type& const_reference; - - hasher hash_funct() const { return _M_hash; } - key_equal key_eq() const { return _M_equals; } - -private: - typedef _Hashtable_node<_Val> _Node; - -public: - typedef typename _Alloc::template rebind<_Val>::other allocator_type; - allocator_type get_allocator() const { return _M_node_allocator; } - -private: - typedef - typename _Alloc::template rebind<_Node>::other _M_node_allocator_type; - typedef - typename _Alloc::template rebind<_Node*>::other _M_node_ptr_allocator_type; - typedef std::vector<_Node*, _M_node_ptr_allocator_type> _M_buckets_type; - -private: - _M_node_allocator_type _M_node_allocator; - hasher _M_hash; - key_equal _M_equals; - _ExtractKey _M_get_key; - _M_buckets_type _M_buckets; - size_type _M_num_elements; - - _Node* _M_get_node() { return _M_node_allocator.allocate(1); } - void _M_put_node(_Node* __p) { _M_node_allocator.deallocate(__p, 1); } - -public: - typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, - _Alloc> - iterator; - typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc> - const_iterator; - - friend struct _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc>; - friend struct _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc>; - -public: - hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql, - const _ExtractKey& __ext, - const allocator_type& __a = allocator_type()) - : _M_node_allocator(__a) - , _M_hash(__hf) - , _M_equals(__eql) - , _M_get_key(__ext) - , _M_buckets(__a) - , _M_num_elements(0) - { - _M_initialize_buckets(__n); - } - - hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql, - const allocator_type& __a = allocator_type()) - : _M_node_allocator(__a) - , _M_hash(__hf) - , _M_equals(__eql) - , _M_get_key(_ExtractKey()) - , _M_buckets(__a) - , _M_num_elements(0) - { - _M_initialize_buckets(__n); - } - - hashtable(const hashtable& __ht) - : _M_node_allocator(__ht.get_allocator()) - , _M_hash(__ht._M_hash) - , _M_equals(__ht._M_equals) - , _M_get_key(__ht._M_get_key) - , _M_buckets(__ht.get_allocator()) - , _M_num_elements(0) - { - _M_copy_from(__ht); - } - - hashtable& operator=(const hashtable& __ht) - { - if (&__ht != this) { - clear(); - _M_hash = __ht._M_hash; - _M_equals = __ht._M_equals; - _M_get_key = __ht._M_get_key; - _M_copy_from(__ht); - } - return *this; - } - - ~hashtable() { clear(); } - - size_type size() const { return _M_num_elements; } - size_type max_size() const { return size_type(-1); } - bool empty() const { return size() == 0; } - - void swap(hashtable& __ht) - { - std::swap(_M_hash, __ht._M_hash); - std::swap(_M_equals, __ht._M_equals); - std::swap(_M_get_key, __ht._M_get_key); - _M_buckets.swap(__ht._M_buckets); - std::swap(_M_num_elements, __ht._M_num_elements); - } - - iterator begin() - { - for (size_type __n = 0; __n < _M_buckets.size(); ++__n) - if (_M_buckets[__n]) - return iterator(_M_buckets[__n], this); - return end(); - } - - iterator end() { return iterator(nullptr, this); } - - const_iterator begin() const - { - for (size_type __n = 0; __n < _M_buckets.size(); ++__n) - if (_M_buckets[__n]) - return const_iterator(_M_buckets[__n], this); - return end(); - } - - const_iterator end() const { return const_iterator(nullptr, this); } - - friend bool operator==<>(const hashtable&, const hashtable&); - -public: - size_type bucket_count() const { return _M_buckets.size(); } - - size_type max_bucket_count() const - { - return get_stl_prime_list()[(int)_stl_num_primes - 1]; - } - - size_type elems_in_bucket(size_type __bucket) const - { - size_type __result = 0; - for (_Node* __cur = _M_buckets[__bucket]; __cur; __cur = __cur->_M_next) - __result += 1; - return __result; - } - - std::pair<iterator, bool> insert_unique(const value_type& __obj) - { - resize(_M_num_elements + 1); - return insert_unique_noresize(__obj); - } - - iterator insert_equal(const value_type& __obj) - { - resize(_M_num_elements + 1); - return insert_equal_noresize(__obj); - } - - std::pair<iterator, bool> insert_unique_noresize(const value_type& __obj); - iterator insert_equal_noresize(const value_type& __obj); - - template <class _InputIterator> - void insert_unique(_InputIterator __f, _InputIterator __l) - { - insert_unique( - __f, __l, - typename std::iterator_traits<_InputIterator>::iterator_category()); - } - - template <class _InputIterator> - void insert_equal(_InputIterator __f, _InputIterator __l) - { - insert_equal( - __f, __l, - typename std::iterator_traits<_InputIterator>::iterator_category()); - } - - template <class _InputIterator> - void insert_unique(_InputIterator __f, _InputIterator __l, - std::input_iterator_tag) - { - for (; __f != __l; ++__f) - insert_unique(*__f); - } - - template <class _InputIterator> - void insert_equal(_InputIterator __f, _InputIterator __l, - std::input_iterator_tag) - { - for (; __f != __l; ++__f) - insert_equal(*__f); - } - - template <class _ForwardIterator> - void insert_unique(_ForwardIterator __f, _ForwardIterator __l, - std::forward_iterator_tag) - { - size_type __n = 0; - std::distance(__f, __l, __n); - resize(_M_num_elements + __n); - for (; __n > 0; --__n, ++__f) - insert_unique_noresize(*__f); - } - - template <class _ForwardIterator> - void insert_equal(_ForwardIterator __f, _ForwardIterator __l, - std::forward_iterator_tag) - { - size_type __n = 0; - std::distance(__f, __l, __n); - resize(_M_num_elements + __n); - for (; __n > 0; --__n, ++__f) - insert_equal_noresize(*__f); - } - - reference find_or_insert(const value_type& __obj); - - iterator find(const key_type& __key) - { - size_type __n = _M_bkt_num_key(__key); - _Node* __first; - for (__first = _M_buckets[__n]; - __first && !_M_equals(_M_get_key(__first->_M_val), __key); - __first = __first->_M_next) { - } - return iterator(__first, this); - } - - const_iterator find(const key_type& __key) const - { - size_type __n = _M_bkt_num_key(__key); - const _Node* __first; - for (__first = _M_buckets[__n]; - __first && !_M_equals(_M_get_key(__first->_M_val), __key); - __first = __first->_M_next) { - } - return const_iterator(__first, this); - } - - size_type count(const key_type& __key) const - { - const size_type __n = _M_bkt_num_key(__key); - size_type __result = 0; - - for (const _Node* __cur = _M_buckets[__n]; __cur; __cur = __cur->_M_next) - if (_M_equals(_M_get_key(__cur->_M_val), __key)) - ++__result; - return __result; - } - - std::pair<iterator, iterator> equal_range(const key_type& __key); - - std::pair<const_iterator, const_iterator> equal_range( - const key_type& __key) const; - - size_type erase(const key_type& __key); - void erase(const iterator& __it); - void erase(iterator __first, iterator __last); - - void erase(const const_iterator& __it); - void erase(const_iterator __first, const_iterator __last); - - void resize(size_type __num_elements_hint); - void clear(); - -private: - size_type _M_next_size(size_type __n) const { return _stl_next_prime(__n); } - - void _M_initialize_buckets(size_type __n) - { - const size_type __n_buckets = _M_next_size(__n); - _M_buckets.reserve(__n_buckets); - _M_buckets.insert(_M_buckets.end(), __n_buckets, (_Node*)nullptr); - _M_num_elements = 0; - } - - size_type _M_bkt_num_key(const key_type& __key) const - { - return _M_bkt_num_key(__key, _M_buckets.size()); - } - - size_type _M_bkt_num(const value_type& __obj) const - { - return _M_bkt_num_key(_M_get_key(__obj)); - } - - size_type _M_bkt_num_key(const key_type& __key, size_t __n) const - { - return _M_hash(__key) % __n; - } - - size_type _M_bkt_num(const value_type& __obj, size_t __n) const - { - return _M_bkt_num_key(_M_get_key(__obj), __n); - } - - void construct(_Val* p, const _Val& v) { new (p) _Val(v); } - void destroy(_Val* p) - { - (void)p; - p->~_Val(); - } - - _Node* _M_new_node(const value_type& __obj) - { - _Node* __n = _M_get_node(); - __n->_M_next = nullptr; - try { - construct(&__n->_M_val, __obj); - return __n; - } catch (...) { - _M_put_node(__n); - throw; - } - } - - void _M_delete_node(_Node* __n) - { - destroy(&__n->_M_val); - _M_put_node(__n); - } - - void _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last); - void _M_erase_bucket(const size_type __n, _Node* __last); - - void _M_copy_from(const hashtable& __ht); -}; - -template <class _Val, class _Key, class _HF, class _ExK, class _EqK, - class _All> -_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>& -_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++() -{ - const _Node* __old = _M_cur; - _M_cur = _M_cur->_M_next; - if (!_M_cur) { - size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val); - while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size()) - _M_cur = _M_ht->_M_buckets[__bucket]; - } - return *this; -} - -template <class _Val, class _Key, class _HF, class _ExK, class _EqK, - class _All> -inline _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All> -_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int) -{ - iterator __tmp = *this; - ++*this; - return __tmp; -} - -template <class _Val, class _Key, class _HF, class _ExK, class _EqK, - class _All> -_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>& -_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++() -{ - const _Node* __old = _M_cur; - _M_cur = _M_cur->_M_next; - if (!_M_cur) { - size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val); - while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size()) - _M_cur = _M_ht->_M_buckets[__bucket]; - } - return *this; -} - -template <class _Val, class _Key, class _HF, class _ExK, class _EqK, - class _All> -inline _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All> -_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int) -{ - const_iterator __tmp = *this; - ++*this; - return __tmp; -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, - const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2) -{ - typedef typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_Node _Node; - if (__ht1._M_buckets.size() != __ht2._M_buckets.size()) - return false; - for (int __n = 0; __n < __ht1._M_buckets.size(); ++__n) { - _Node* __cur1 = __ht1._M_buckets[__n]; - _Node* __cur2 = __ht2._M_buckets[__n]; - for (; __cur1 && __cur2 && __cur1->_M_val == __cur2->_M_val; - __cur1 = __cur1->_M_next, __cur2 = __cur2->_M_next) { - } - if (__cur1 || __cur2) - return false; - } - return true; -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -inline bool operator!=(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, - const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2) -{ - return !(__ht1 == __ht2); -} - -template <class _Val, class _Key, class _HF, class _Extract, class _EqKey, - class _All> -inline void swap(hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht1, - hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht2) -{ - __ht1.swap(__ht2); -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -std::pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator, bool> -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::insert_unique_noresize( - const value_type& __obj) -{ - const size_type __n = _M_bkt_num(__obj); - _Node* __first = _M_buckets[__n]; - - for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) - if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) - return std::pair<iterator, bool>(iterator(__cur, this), false); - - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __first; - _M_buckets[__n] = __tmp; - ++_M_num_elements; - return std::pair<iterator, bool>(iterator(__tmp, this), true); -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::insert_equal_noresize( - const value_type& __obj) -{ - const size_type __n = _M_bkt_num(__obj); - _Node* __first = _M_buckets[__n]; - - for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) - if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) { - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __cur->_M_next; - __cur->_M_next = __tmp; - ++_M_num_elements; - return iterator(__tmp, this); - } - - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __first; - _M_buckets[__n] = __tmp; - ++_M_num_elements; - return iterator(__tmp, this); -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::reference -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::find_or_insert( - const value_type& __obj) -{ - resize(_M_num_elements + 1); - - size_type __n = _M_bkt_num(__obj); - _Node* __first = _M_buckets[__n]; - - for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) - if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) - return __cur->_M_val; - - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __first; - _M_buckets[__n] = __tmp; - ++_M_num_elements; - return __tmp->_M_val; -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -std::pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator, - typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator> -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::equal_range(const key_type& __key) -{ - typedef std::pair<iterator, iterator> _Pii; - const size_type __n = _M_bkt_num_key(__key); - - for (_Node* __first = _M_buckets[__n]; __first; __first = __first->_M_next) - if (_M_equals(_M_get_key(__first->_M_val), __key)) { - for (_Node* __cur = __first->_M_next; __cur; __cur = __cur->_M_next) - if (!_M_equals(_M_get_key(__cur->_M_val), __key)) - return _Pii(iterator(__first, this), iterator(__cur, this)); - for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m) - if (_M_buckets[__m]) - return _Pii(iterator(__first, this), - iterator(_M_buckets[__m], this)); - return _Pii(iterator(__first, this), end()); - } - return _Pii(end(), end()); -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -std::pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator, - typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator> -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::equal_range( - const key_type& __key) const -{ - typedef std::pair<const_iterator, const_iterator> _Pii; - const size_type __n = _M_bkt_num_key(__key); - - for (const _Node* __first = _M_buckets[__n]; __first; - __first = __first->_M_next) { - if (_M_equals(_M_get_key(__first->_M_val), __key)) { - for (const _Node* __cur = __first->_M_next; __cur; - __cur = __cur->_M_next) - if (!_M_equals(_M_get_key(__cur->_M_val), __key)) - return _Pii(const_iterator(__first, this), - const_iterator(__cur, this)); - for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m) - if (_M_buckets[__m]) - return _Pii(const_iterator(__first, this), - const_iterator(_M_buckets[__m], this)); - return _Pii(const_iterator(__first, this), end()); - } - } - return _Pii(end(), end()); -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::size_type -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const key_type& __key) -{ - const size_type __n = _M_bkt_num_key(__key); - _Node* __first = _M_buckets[__n]; - size_type __erased = 0; - - if (__first) { - _Node* __cur = __first; - _Node* __next = __cur->_M_next; - while (__next) { - if (_M_equals(_M_get_key(__next->_M_val), __key)) { - __cur->_M_next = __next->_M_next; - _M_delete_node(__next); - __next = __cur->_M_next; - ++__erased; - --_M_num_elements; - } else { - __cur = __next; - __next = __cur->_M_next; - } - } - if (_M_equals(_M_get_key(__first->_M_val), __key)) { - _M_buckets[__n] = __first->_M_next; - _M_delete_node(__first); - ++__erased; - --_M_num_elements; - } - } - return __erased; -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const iterator& __it) -{ - _Node* __p = __it._M_cur; - if (__p) { - const size_type __n = _M_bkt_num(__p->_M_val); - _Node* __cur = _M_buckets[__n]; - - if (__cur == __p) { - _M_buckets[__n] = __cur->_M_next; - _M_delete_node(__cur); - --_M_num_elements; - } else { - _Node* __next = __cur->_M_next; - while (__next) { - if (__next == __p) { - __cur->_M_next = __next->_M_next; - _M_delete_node(__next); - --_M_num_elements; - break; - } else { - __cur = __next; - __next = __cur->_M_next; - } - } - } - } -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(iterator __first, - iterator __last) -{ - size_type __f_bucket = - __first._M_cur ? _M_bkt_num(__first._M_cur->_M_val) : _M_buckets.size(); - size_type __l_bucket = - __last._M_cur ? _M_bkt_num(__last._M_cur->_M_val) : _M_buckets.size(); - - if (__first._M_cur == __last._M_cur) - return; - else if (__f_bucket == __l_bucket) - _M_erase_bucket(__f_bucket, __first._M_cur, __last._M_cur); - else { - _M_erase_bucket(__f_bucket, __first._M_cur, nullptr); - for (size_type __n = __f_bucket + 1; __n < __l_bucket; ++__n) - _M_erase_bucket(__n, nullptr); - if (__l_bucket != _M_buckets.size()) - _M_erase_bucket(__l_bucket, __last._M_cur); - } -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase( - const_iterator __first, const_iterator __last) -{ - erase(iterator(const_cast<_Node*>(__first._M_cur), - const_cast<hashtable*>(__first._M_ht)), - iterator(const_cast<_Node*>(__last._M_cur), - const_cast<hashtable*>(__last._M_ht))); -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase( - const const_iterator& __it) -{ - erase(iterator(const_cast<_Node*>(__it._M_cur), - const_cast<hashtable*>(__it._M_ht))); -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::resize( - size_type __num_elements_hint) -{ - const size_type __old_n = _M_buckets.size(); - if (__num_elements_hint > __old_n) { - const size_type __n = _M_next_size(__num_elements_hint); - if (__n > __old_n) { - _M_buckets_type __tmp(__n, (_Node*)(nullptr), - _M_buckets.get_allocator()); - try { - for (size_type __bucket = 0; __bucket < __old_n; ++__bucket) { - _Node* __first = _M_buckets[__bucket]; - while (__first) { - size_type __new_bucket = _M_bkt_num(__first->_M_val, __n); - _M_buckets[__bucket] = __first->_M_next; - __first->_M_next = __tmp[__new_bucket]; - __tmp[__new_bucket] = __first; - __first = _M_buckets[__bucket]; - } - } - _M_buckets.swap(__tmp); - } catch (...) { - for (size_type __bucket = 0; __bucket < __tmp.size(); ++__bucket) { - while (__tmp[__bucket]) { - _Node* __next = __tmp[__bucket]->_M_next; - _M_delete_node(__tmp[__bucket]); - __tmp[__bucket] = __next; - } - } - throw; - } - } - } -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket( - const size_type __n, _Node* __first, _Node* __last) -{ - _Node* __cur = _M_buckets[__n]; - if (__cur == __first) - _M_erase_bucket(__n, __last); - else { - _Node* __next; - for (__next = __cur->_M_next; __next != __first; - __cur = __next, __next = __cur->_M_next) - ; - while (__next != __last) { - __cur->_M_next = __next->_M_next; - _M_delete_node(__next); - __next = __cur->_M_next; - --_M_num_elements; - } - } -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket( - const size_type __n, _Node* __last) -{ - _Node* __cur = _M_buckets[__n]; - while (__cur != __last) { - _Node* __next = __cur->_M_next; - _M_delete_node(__cur); - __cur = __next; - _M_buckets[__n] = __cur; - --_M_num_elements; - } -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::clear() -{ - for (size_type __i = 0; __i < _M_buckets.size(); ++__i) { - _Node* __cur = _M_buckets[__i]; - while (__cur != nullptr) { - _Node* __next = __cur->_M_next; - _M_delete_node(__cur); - __cur = __next; - } - _M_buckets[__i] = nullptr; - } - _M_num_elements = 0; -} - -template <class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_copy_from( - const hashtable& __ht) -{ - _M_buckets.clear(); - _M_buckets.reserve(__ht._M_buckets.size()); - _M_buckets.insert(_M_buckets.end(), __ht._M_buckets.size(), (_Node*)nullptr); - try { - for (size_type __i = 0; __i < __ht._M_buckets.size(); ++__i) { - const _Node* __cur = __ht._M_buckets[__i]; - if (__cur) { - _Node* __copy = _M_new_node(__cur->_M_val); - _M_buckets[__i] = __copy; - - for (_Node* __next = __cur->_M_next; __next; - __cur = __next, __next = __cur->_M_next) { - __copy->_M_next = _M_new_node(__next->_M_val); - __copy = __copy->_M_next; - } - } - } - _M_num_elements = __ht._M_num_elements; - } catch (...) { - clear(); - throw; - } -} - -} // namespace @KWSYS_NAMESPACE@ - -// Undo warning suppression. -# if defined(__clang__) && defined(__has_warning) -# if __has_warning("-Wdeprecated") -# pragma clang diagnostic pop -# endif -# endif - -# if defined(_MSC_VER) -# pragma warning(pop) -# endif - -#endif diff --git a/Source/kwsys/kwsysPlatformTests.cmake b/Source/kwsys/kwsysPlatformTests.cmake index 28d3f68e2..89be4b885 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/kwsysPlatformTestsC.c b/Source/kwsys/kwsysPlatformTestsC.c index b0cf7ad3b..d44f7eb9c 100644 --- a/Source/kwsys/kwsysPlatformTestsC.c +++ b/Source/kwsys/kwsysPlatformTestsC.c @@ -69,40 +69,3 @@ int KWSYS_PLATFORM_TEST_C_MAIN() return clock_gettime(CLOCK_MONOTONIC, &ts); } #endif - -#ifdef TEST_KWSYS_C_TYPE_MACROS -char* info_macros = -# if defined(__SIZEOF_SHORT__) - "INFO:macro[__SIZEOF_SHORT__]\n" -# endif -# if defined(__SIZEOF_INT__) - "INFO:macro[__SIZEOF_INT__]\n" -# endif -# if defined(__SIZEOF_LONG__) - "INFO:macro[__SIZEOF_LONG__]\n" -# endif -# if defined(__SIZEOF_LONG_LONG__) - "INFO:macro[__SIZEOF_LONG_LONG__]\n" -# endif -# if defined(__SHORT_MAX__) - "INFO:macro[__SHORT_MAX__]\n" -# endif -# if defined(__INT_MAX__) - "INFO:macro[__INT_MAX__]\n" -# endif -# if defined(__LONG_MAX__) - "INFO:macro[__LONG_MAX__]\n" -# endif -# if defined(__LONG_LONG_MAX__) - "INFO:macro[__LONG_LONG_MAX__]\n" -# endif - ""; - -int KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) -{ - int require = 0; - require += info_macros[argc]; - (void)argv; - return require; -} -#endif diff --git a/Source/kwsys/kwsysPlatformTestsCXX.cxx b/Source/kwsys/kwsysPlatformTestsCXX.cxx index cfd5666f3..0bfa20ee1 100644 --- a/Source/kwsys/kwsysPlatformTestsCXX.cxx +++ b/Source/kwsys/kwsysPlatformTestsCXX.cxx @@ -1,36 +1,5 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifdef TEST_KWSYS_CXX_HAS_CSTDIO -# include <cstdio> -int main() -{ - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_LONG_LONG -long long f(long long n) -{ - return n; -} -int main() -{ - long long n = 0; - return static_cast<int>(f(n)); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS___INT64 -__int64 f(__int64 n) -{ - return n; -} -int main() -{ - __int64 n = 0; - return static_cast<int>(f(n)); -} -#endif #ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIM # include <sys/types.h> @@ -60,82 +29,6 @@ int main() } #endif -#ifdef TEST_KWSYS_CXX_SAME_LONG_AND___INT64 -void function(long**) -{ -} -int main() -{ - __int64** p = 0; - function(p); - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_SAME_LONG_LONG_AND___INT64 -void function(long long**) -{ -} -int main() -{ - __int64** p = 0; - function(p); - return 0; -} -#endif - -#ifdef TEST_KWSYS_IOS_HAS_ISTREAM_LONG_LONG -# include <iostream> -int test_istream(std::istream& is, long long& x) -{ - return (is >> x) ? 1 : 0; -} -int main() -{ - long long x = 0; - return test_istream(std::cin, x); -} -#endif - -#ifdef TEST_KWSYS_IOS_HAS_OSTREAM_LONG_LONG -# include <iostream> -int test_ostream(std::ostream& os, long long x) -{ - return (os << x) ? 1 : 0; -} -int main() -{ - long long x = 0; - return test_ostream(std::cout, x); -} -#endif - -#ifdef TEST_KWSYS_IOS_HAS_ISTREAM___INT64 -# include <iostream> -int test_istream(std::istream& is, __int64& x) -{ - return (is >> x) ? 1 : 0; -} -int main() -{ - __int64 x = 0; - return test_istream(std::cin, x); -} -#endif - -#ifdef TEST_KWSYS_IOS_HAS_OSTREAM___INT64 -# include <iostream> -int test_ostream(std::ostream& os, __int64 x) -{ - return (os << x) ? 1 : 0; -} -int main() -{ - __int64 x = 0; - return test_ostream(std::cout, x); -} -#endif - #ifdef TEST_KWSYS_CXX_HAS_SETENV # include <stdlib.h> int main() @@ -184,33 +77,6 @@ int main() } #endif -#ifdef TEST_KWSYS_CXX_HAS_ATOLL -# include <stdlib.h> -int main() -{ - const char* str = "1024"; - return static_cast<int>(atoll(str)); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_ATOL -# include <stdlib.h> -int main() -{ - const char* str = "1024"; - return static_cast<int>(atol(str)); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS__ATOI64 -# include <stdlib.h> -int main() -{ - const char* str = "1024"; - return static_cast<int>(_atoi64(str)); -} -#endif - #ifdef TEST_KWSYS_CXX_HAS_UTIMES # include <sys/time.h> int main() @@ -288,33 +154,6 @@ int main() } #endif -#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM -int main() -{ - int a = 1; - __asm { - xor EBX, EBX; - mov a, EBX; - } - - return a; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM_CPUID -int main() -{ - int a = 0; - __asm { - xor EAX, EAX; - cpuid; - mov a, EAX; - } - - return a; -} -#endif - #ifdef TEST_KWSYS_STL_HAS_WSTRING # include <string> void f(std::wstring*) diff --git a/Source/kwsys/testCommandLineArguments.cxx b/Source/kwsys/testCommandLineArguments.cxx index 1778a9ba8..078675159 100644 --- a/Source/kwsys/testCommandLineArguments.cxx +++ b/Source/kwsys/testCommandLineArguments.cxx @@ -12,8 +12,8 @@ #include <iostream> #include <vector> -#include <stddef.h> /* size_t */ -#include <string.h> /* strcmp */ +#include <cstddef> /* size_t */ +#include <cstring> /* strcmp */ static void* random_ptr = reinterpret_cast<void*>(0x123); @@ -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 64561b1e3..2f6b73578 100644 --- a/Source/kwsys/testCommandLineArguments1.cxx +++ b/Source/kwsys/testCommandLineArguments1.cxx @@ -12,8 +12,8 @@ #include <iostream> #include <vector> -#include <assert.h> /* assert */ -#include <string.h> /* strcmp */ +#include <cassert> /* assert */ +#include <cstring> /* strcmp */ int testCommandLineArguments1(int argc, char* argv[]) { @@ -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"); @@ -51,9 +51,7 @@ int testCommandLineArguments1(int argc, char* argv[]) std::cout << "Value of N: " << n << std::endl; std::cout << "Value of M: " << m << std::endl; std::cout << "Value of P: " << p << std::endl; - if (m) { - delete[] m; - } + delete[] m; char** newArgv = nullptr; int newArgc = 0; diff --git a/Source/kwsys/testDirectory.cxx b/Source/kwsys/testDirectory.cxx index b1ab0c872..eb3ca3254 100644 --- a/Source/kwsys/testDirectory.cxx +++ b/Source/kwsys/testDirectory.cxx @@ -57,7 +57,11 @@ int _doLongPathTest() Directory testdir; // Set res to failure if the directory doesn't load - res += !testdir.Load(testdirpath); + std::string errorMessage = ""; + res += !testdir.Load(testdirpath, &errorMessage); + if (errorMessage != "") { + std::cerr << "Failed to list directory: " << errorMessage << std::endl; + } // Increment res failure if the directory appears empty res += testdir.GetNumberOfFiles() == 0; // Increment res failures if the path has changed from @@ -73,6 +77,34 @@ int _doLongPathTest() return res; } +int _nonExistentDirectoryTest() +{ + using namespace kwsys; + int res = 0; + std::string testdirpath(TEST_SYSTEMTOOLS_BINARY_DIR + "/directory_testing/doesnt_exist/"); + std::string errorMessage; + Directory testdir; + + errorMessage = "foo"; + // Increment res failure if directory lists + res += testdir.Load(testdirpath, &errorMessage); +#if !defined(_WIN32) || defined(__CYGWIN__) + // Increment res failure if errorMessage is unmodified + res += (errorMessage == "foo"); +#endif + + errorMessage = "foo"; + // Increment res failure if directory has files + res += (testdir.GetNumberOfFilesInDirectory(testdirpath, &errorMessage) > 0); +#if !defined(_WIN32) || defined(__CYGWIN__) + // Increment res failure if errorMessage is unmodified + res += (errorMessage == "foo"); +#endif + + return res; +} + int _copyDirectoryTest() { using namespace kwsys; @@ -106,5 +138,6 @@ int _copyDirectoryTest() int testDirectory(int, char* []) { - return _doLongPathTest() + _copyDirectoryTest(); + return _doLongPathTest() + _nonExistentDirectoryTest() + + _copyDirectoryTest(); } diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx index 2421ac0e1..703ad4dcd 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/testDynload.c b/Source/kwsys/testDynload.c index c49f747df..33a431e9d 100644 --- a/Source/kwsys/testDynload.c +++ b/Source/kwsys/testDynload.c @@ -8,6 +8,6 @@ DL_EXPORT int TestDynamicLoaderData = 0; -DL_EXPORT void TestDynamicLoaderSymbolPointer() +DL_EXPORT void TestDynamicLoaderSymbolPointer(void) { } diff --git a/Source/kwsys/testEncoding.cxx b/Source/kwsys/testEncoding.cxx index 988697bff..ee93e8d8d 100644 --- a/Source/kwsys/testEncoding.cxx +++ b/Source/kwsys/testEncoding.cxx @@ -10,10 +10,10 @@ #include KWSYS_HEADER(Encoding.h) #include <algorithm> +#include <clocale> +#include <cstdlib> +#include <cstring> #include <iostream> -#include <locale.h> -#include <stdlib.h> -#include <string.h> // Work-around CMake dependency scanning limitation. This must // duplicate the above list of headers. @@ -59,7 +59,7 @@ static int testHelloWorldEncoding() std::string str2 = kwsys::Encoding::ToNarrow(wstr); wchar_t* c_wstr = kwsysEncoding_DupToWide(str.c_str()); char* c_str2 = kwsysEncoding_DupToNarrow(c_wstr); - if (!wstr.empty() && (str != str2 || strcmp(c_str2, str.c_str()))) { + if (!wstr.empty() && (str != str2 || strcmp(c_str2, str.c_str()) != 0)) { std::cout << "converted string was different: " << str2 << std::endl; std::cout << "converted string was different: " << c_str2 << std::endl; ret++; @@ -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/testFStream.cxx b/Source/kwsys/testFStream.cxx index 5009e9887..afba9530e 100644 --- a/Source/kwsys/testFStream.cxx +++ b/Source/kwsys/testFStream.cxx @@ -7,10 +7,7 @@ #endif #include KWSYS_HEADER(FStream.hxx) -#include <string.h> -#ifdef __BORLANDC__ -# include <mem.h> /* memcmp */ -#endif +#include <cstring> // Work-around CMake dependency scanning limitation. This must // duplicate the above list of headers. diff --git a/Source/kwsys/testHashSTL.cxx b/Source/kwsys/testHashSTL.cxx deleted file mode 100644 index 4ed2f899d..000000000 --- a/Source/kwsys/testHashSTL.cxx +++ /dev/null @@ -1,64 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(hash_map.hxx) -#include KWSYS_HEADER(hash_set.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "hash_map.hxx.in" -# include "hash_set.hxx.in" -#endif - -#include <iostream> - -#if defined(_MSC_VER) -# pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) -# pragma set woff 1468 /* inline function cannot be explicitly instantiated \ - */ -#endif - -template class kwsys::hash_map<const char*, int>; -template class kwsys::hash_set<int>; - -static bool test_hash_map() -{ - typedef kwsys::hash_map<const char*, int> mtype; - 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 << "]" - << std::endl; - sum += mi->second; - } - return sum == 3; -} - -static bool test_hash_set() -{ - typedef kwsys::hash_set<int> stype; - 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; - } - return sum == 3; -} - -int testHashSTL(int, char* []) -{ - bool result = true; - result = test_hash_map() && result; - result = test_hash_set() && result; - return result ? 0 : 1; -} diff --git a/Source/kwsys/testProcess.c b/Source/kwsys/testProcess.c index 39aaa23ba..0c658f566 100644 --- a/Source/kwsys/testProcess.c +++ b/Source/kwsys/testProcess.c @@ -24,10 +24,6 @@ # include <unistd.h> #endif -#if defined(__BORLANDC__) -# pragma warn - 8060 /* possibly incorrect assignment */ -#endif - /* Platform-specific sleep functions. */ #if defined(__BEOS__) && !defined(__ZETA__) @@ -631,7 +627,8 @@ int main(int argc, const char* argv[]) } fprintf(stderr, "Invalid test number %d.\n", n); return 1; - } else if (n >= 1 && n <= 10) { + } + if (n >= 1 && n <= 10) { /* This is the parent process for a requested test number. */ int states[10] = { kwsysProcess_State_Exited, kwsysProcess_State_Exited, @@ -709,7 +706,8 @@ int main(int argc, const char* argv[]) free(argv0); #endif return r; - } else if (argc > 2 && strcmp(argv[1], "0") == 0) { + } + if (argc > 2 && strcmp(argv[1], "0") == 0) { /* This is the special debugging test to run a given command line. */ const char** cmd = argv + 2; @@ -720,9 +718,8 @@ int main(int argc, const char* argv[]) int r = runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1, 0, 0, 0); return r; - } else { - /* Improper usage. */ - fprintf(stdout, "Usage: %s <test number>\n", argv[0]); - return 1; } + /* Improper usage. */ + fprintf(stdout, "Usage: %s <test number>\n", argv[0]); + return 1; } diff --git a/Source/kwsys/testSystemInformation.cxx b/Source/kwsys/testSystemInformation.cxx index 154517eae..4f0c522e4 100644 --- a/Source/kwsys/testSystemInformation.cxx +++ b/Source/kwsys/testSystemInformation.cxx @@ -11,29 +11,13 @@ #include <iostream> -#if defined(KWSYS_USE_LONG_LONG) -# if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) -# define iostreamLongLong(x) (x) -# else -# define iostreamLongLong(x) ((long)x) -# endif -#elif defined(KWSYS_USE___INT64) -# if defined(KWSYS_IOS_HAS_OSTREAM___INT64) -# define iostreamLongLong(x) (x) -# else -# define iostreamLongLong(x) ((long)x) -# endif -#else -# error "No Long Long" -#endif - #define printMethod(info, m) std::cout << #m << ": " << info.m() << "\n" #define printMethod2(info, m, unit) \ std::cout << #m << ": " << info.m() << " " << unit << "\n" #define printMethod3(info, m, unit) \ - std::cout << #m << ": " << iostreamLongLong(info.m) << " " << unit << "\n" + std::cout << #m << ": " << info.m << " " << unit << "\n" int testSystemInformation(int, char* []) { diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index 3f6eeb8c1..1d3461443 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -20,18 +20,18 @@ // left on disk. #include <testSystemTools.h> +#include <cstdlib> /* free */ +#include <cstring> /* strcmp */ #include <iostream> #include <sstream> -#include <stdlib.h> /* free */ -#include <string.h> /* strcmp */ #if defined(_WIN32) && !defined(__CYGWIN__) -# include <io.h> /* _umask (MSVC) / umask (Borland) */ +# include <io.h> /* _umask (MSVC) */ # ifdef _MSC_VER -# define umask _umask // Note this is still umask on Borland +# define umask _umask # endif #endif #include <sys/stat.h> /* umask (POSIX), _S_I* constants (Windows) */ -// Visual C++ does not define mode_t (note that Borland does, however). +// Visual C++ does not define mode_t. #if defined(_MSC_VER) typedef unsigned short mode_t; #endif @@ -328,7 +328,14 @@ static bool CheckFileOperations() } // While we're at it, check proper TestFileAccess functionality. - if (kwsys::SystemTools::TestFileAccess(testNewFile, + bool do_write_test = true; +#if defined(__linux__) + // If we are running as root on linux ignore this check, as + // root can always write to files + do_write_test = (getuid() != 0); +#endif + if (do_write_test && + kwsys::SystemTools::TestFileAccess(testNewFile, kwsys::TEST_FILE_WRITE)) { std::cerr << "TestFileAccess incorrectly indicated that this is a writable file:" @@ -500,7 +507,7 @@ static bool CheckStringOperations() char* cres = kwsys::SystemTools::AppendStrings("Mary Had A", " Little Lamb."); - if (strcmp(cres, "Mary Had A Little Lamb.")) { + if (strcmp(cres, "Mary Had A Little Lamb.") != 0) { std::cerr << "Problem with AppendStrings " << "\"Mary Had A\" \" Little Lamb.\"" << std::endl; res = false; @@ -508,7 +515,7 @@ static bool CheckStringOperations() delete[] cres; cres = kwsys::SystemTools::AppendStrings("Mary Had", " A ", "Little Lamb."); - if (strcmp(cres, "Mary Had A Little Lamb.")) { + if (strcmp(cres, "Mary Had A Little Lamb.") != 0) { std::cerr << "Problem with AppendStrings " << "\"Mary Had\" \" A \" \"Little Lamb.\"" << std::endl; res = false; @@ -522,7 +529,7 @@ static bool CheckStringOperations() } cres = kwsys::SystemTools::RemoveChars("Mary Had A Little Lamb.", "aeiou"); - if (strcmp(cres, "Mry Hd A Lttl Lmb.")) { + if (strcmp(cres, "Mry Hd A Lttl Lmb.") != 0) { std::cerr << "Problem with RemoveChars " << "\"Mary Had A Little Lamb.\"" << std::endl; res = false; @@ -530,7 +537,7 @@ static bool CheckStringOperations() delete[] cres; cres = kwsys::SystemTools::RemoveCharsButUpperHex("Mary Had A Little Lamb."); - if (strcmp(cres, "A")) { + if (strcmp(cres, "A") != 0) { std::cerr << "Problem with RemoveCharsButUpperHex " << "\"Mary Had A Little Lamb.\"" << std::endl; res = false; @@ -539,7 +546,7 @@ static bool CheckStringOperations() char* cres2 = strdup("Mary Had A Little Lamb."); kwsys::SystemTools::ReplaceChars(cres2, "aeiou", 'X'); - if (strcmp(cres2, "MXry HXd A LXttlX LXmb.")) { + if (strcmp(cres2, "MXry HXd A LXttlX LXmb.") != 0) { std::cerr << "Problem with ReplaceChars " << "\"Mary Had A Little Lamb.\"" << std::endl; res = false; @@ -561,7 +568,7 @@ static bool CheckStringOperations() } cres = kwsys::SystemTools::DuplicateString("Mary Had A Little Lamb."); - if (strcmp(cres, "Mary Had A Little Lamb.")) { + if (strcmp(cres, "Mary Had A Little Lamb.") != 0) { std::cerr << "Problem with DuplicateString " << "\"Mary Had A Little Lamb.\"" << std::endl; res = false; @@ -721,8 +728,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 +749,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 +823,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: " @@ -1086,6 +1092,70 @@ static bool CheckCopyFileIfDifferent() 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; +} + +static bool CheckSplitString() +{ + bool ret = true; + + auto check_split = [](std::string const& input, + std::initializer_list<const char*> expected) -> bool { + auto const components = kwsys::SystemTools::SplitString(input, '/'); + if (components.size() != expected.size()) { + std::cerr << "Incorrect split count for " << input << ": " + << components.size() << std::endl; + return false; + } + size_t i = 0; + for (auto& part : expected) { + if (components[i] != part) { + std::cerr << "Incorrect split component " << i << " for " << input + << ": " << components[i] << std::endl; + return false; + } + ++i; + } + return true; + }; + + // No separators + ret &= check_split("nosep", { "nosep" }); + // Simple + ret &= check_split("first/second", { "first", "second" }); + // Separator at beginning + ret &= check_split("/starts/sep", { "", "starts", "sep" }); + // Separator at end + ret &= check_split("ends/sep/", { "ends", "sep", "" }); + + return ret; +} + int testSystemTools(int, char* []) { bool res = true; @@ -1133,5 +1203,9 @@ int testSystemTools(int, char* []) res &= CheckCopyFileIfDifferent(); + res &= CheckURLParsing(); + + res &= CheckSplitString(); + return res ? 0 : 1; } diff --git a/Source/kwsys/testSystemTools.h.in b/Source/kwsys/testSystemTools.h.in index 022e36e2f..e4b89a7c1 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@" |