diff options
Diffstat (limited to 'Source')
183 files changed, 4372 insertions, 3186 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 1b6bb00..ee8767f 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -412,6 +412,8 @@ set(SRCS cmSourceFileLocationKind.h cmSourceGroup.cxx cmSourceGroup.h + cmStandardLevelResolver.cxx + cmStandardLevelResolver.h cmState.cxx cmState.h cmStateDirectory.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index cdadbe7..9b2b4ac 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 18) -set(CMake_VERSION_PATCH 1) +set(CMake_VERSION_PATCH 20200820) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index 72af10b..8b3644f 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -221,6 +221,7 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration() this->LightExtensions.insert("WixUIExtension"); CollectExtensions("CPACK_WIX_EXTENSIONS", this->LightExtensions); CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", this->LightExtensions); + CollectXmlNamespaces("CPACK_WIX_CUSTOM_XMLNS", this->CustomXmlNamespaces); const char* patchFilePath = GetOption("CPACK_WIX_PATCH_FILE"); if (patchFilePath) { @@ -322,6 +323,7 @@ void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() cmWIXSourceWriter includeFile(this->Logger, includeFilename, this->ComponentGuidType, cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT); + InjectXmlNamespaces(includeFile); CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_GUID"); CopyDefinition(includeFile, "CPACK_WIX_UPGRADE_GUID"); @@ -345,6 +347,7 @@ void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile() cmWIXSourceWriter includeFile(this->Logger, includeFilename, this->ComponentGuidType, cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT); + InjectXmlNamespaces(includeFile); std::string prefix = "CPACK_WIX_PROPERTY_"; std::vector<std::string> options = GetOptions(); @@ -393,6 +396,7 @@ void cmCPackWIXGenerator::CreateWiXProductFragmentIncludeFile() cmWIXSourceWriter includeFile(this->Logger, includeFilename, this->ComponentGuidType, cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT); + InjectXmlNamespaces(includeFile); this->Patch->ApplyFragment("#PRODUCT", includeFile); } @@ -432,6 +436,7 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() cmWIXDirectoriesSourceWriter directoryDefinitions( this->Logger, directoryDefinitionsFilename, this->ComponentGuidType); + InjectXmlNamespaces(directoryDefinitions); directoryDefinitions.BeginElement("Fragment"); std::string installRoot; @@ -453,6 +458,7 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() cmWIXFilesSourceWriter fileDefinitions(this->Logger, fileDefinitionsFilename, this->ComponentGuidType); + InjectXmlNamespaces(fileDefinitions); fileDefinitions.BeginElement("Fragment"); @@ -463,6 +469,7 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() cmWIXFeaturesSourceWriter featureDefinitions( this->Logger, featureDefinitionsFilename, this->ComponentGuidType); + InjectXmlNamespaces(featureDefinitions); featureDefinitions.BeginElement("Fragment"); @@ -1147,6 +1154,35 @@ void cmCPackWIXGenerator::CollectExtensions(std::string const& variableName, extensions.insert(list.begin(), list.end()); } +void cmCPackWIXGenerator::CollectXmlNamespaces(std::string const& variableName, + xmlns_map_t& namespaces) +{ + const char* variableContent = GetOption(variableName.c_str()); + if (!variableContent) { + return; + } + + std::vector<std::string> list = cmExpandedList(variableContent); + for (std::string const& str : list) { + auto pos = str.find('='); + if (pos != std::string::npos) { + auto name = str.substr(0, pos); + auto value = str.substr(pos + 1); + namespaces.emplace(std::make_pair(name, value)); + } else { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Invalid element in CPACK_WIX_CUSTOM_XMLNS ignored: " + << "\"" << str << "\"" << std::endl); + } + } + std::ostringstream oss; + for (auto& ns : namespaces) { + oss << " xmlns:" << ns.first << "=\"" + << cmWIXSourceWriter::EscapeAttributeValue(ns.second) << '"'; + } + SetOption("CPACK_WIX_CUSTOM_XMLNS_EXPANDED", oss.str().c_str()); +} + void cmCPackWIXGenerator::AddCustomFlags(std::string const& variableName, std::ostream& stream) { @@ -1172,3 +1208,10 @@ std::string cmCPackWIXGenerator::RelativePathWithoutComponentPrefix( return path.substr(pos + 1); } + +void cmCPackWIXGenerator::InjectXmlNamespaces(cmWIXSourceWriter& sourceWriter) +{ + for (auto& ns : this->CustomXmlNamespaces) { + sourceWriter.AddAttributeUnlessEmpty("xmlns:" + ns.first, ns.second); + } +} diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h index d5a16ec..b9c37e9 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.h +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -49,6 +49,7 @@ private: using id_map_t = std::map<std::string, std::string>; using ambiguity_map_t = std::map<std::string, size_t>; using extension_set_t = std::set<std::string>; + using xmlns_map_t = std::map<std::string, std::string>; enum class DefinitionType { @@ -147,16 +148,22 @@ private: void CollectExtensions(std::string const& variableName, extension_set_t& extensions); + void CollectXmlNamespaces(std::string const& variableName, + xmlns_map_t& namespaces); + void AddCustomFlags(std::string const& variableName, std::ostream& stream); std::string RelativePathWithoutComponentPrefix(std::string const& path); + void InjectXmlNamespaces(cmWIXSourceWriter& sourceWriter); + std::vector<std::string> WixSources; id_map_t PathToIdMap; ambiguity_map_t IdAmbiguityCounter; extension_set_t CandleExtensions; extension_set_t LightExtensions; + xmlns_map_t CustomXmlNamespaces; std::string CPackTopLevel; diff --git a/Source/CPack/WiX/cmWIXSourceWriter.h b/Source/CPack/WiX/cmWIXSourceWriter.h index 8cc2070..6030ea3 100644 --- a/Source/CPack/WiX/cmWIXSourceWriter.h +++ b/Source/CPack/WiX/cmWIXSourceWriter.h @@ -50,6 +50,8 @@ public: std::string CreateGuidFromComponentId(std::string const& componentId); + static std::string EscapeAttributeValue(std::string const& value); + protected: cmCPackLog* Logger; @@ -64,8 +66,6 @@ private: void Indent(size_t count); - static std::string EscapeAttributeValue(std::string const& value); - cmsys::ofstream File; State State; diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index 3d5fe6b..560e5c1 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -696,57 +696,57 @@ int cmCPackDebGenerator::createDeb() const char* debian_pkg_source = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE"); - if (debian_pkg_source && *debian_pkg_source) { + if (cmNonempty(debian_pkg_source)) { controlValues["Source"] = debian_pkg_source; } const char* debian_pkg_dep = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DEPENDS"); - if (debian_pkg_dep && *debian_pkg_dep) { + if (cmNonempty(debian_pkg_dep)) { controlValues["Depends"] = debian_pkg_dep; } const char* debian_pkg_rec = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_RECOMMENDS"); - if (debian_pkg_rec && *debian_pkg_rec) { + if (cmNonempty(debian_pkg_rec)) { controlValues["Recommends"] = debian_pkg_rec; } const char* debian_pkg_sug = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SUGGESTS"); - if (debian_pkg_sug && *debian_pkg_sug) { + if (cmNonempty(debian_pkg_sug)) { controlValues["Suggests"] = debian_pkg_sug; } const char* debian_pkg_url = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_HOMEPAGE"); - if (debian_pkg_url && *debian_pkg_url) { + if (cmNonempty(debian_pkg_url)) { controlValues["Homepage"] = debian_pkg_url; } const char* debian_pkg_predep = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PREDEPENDS"); - if (debian_pkg_predep && *debian_pkg_predep) { + if (cmNonempty(debian_pkg_predep)) { controlValues["Pre-Depends"] = debian_pkg_predep; } const char* debian_pkg_enhances = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ENHANCES"); - if (debian_pkg_enhances && *debian_pkg_enhances) { + if (cmNonempty(debian_pkg_enhances)) { controlValues["Enhances"] = debian_pkg_enhances; } const char* debian_pkg_breaks = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_BREAKS"); - if (debian_pkg_breaks && *debian_pkg_breaks) { + if (cmNonempty(debian_pkg_breaks)) { controlValues["Breaks"] = debian_pkg_breaks; } const char* debian_pkg_conflicts = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONFLICTS"); - if (debian_pkg_conflicts && *debian_pkg_conflicts) { + if (cmNonempty(debian_pkg_conflicts)) { controlValues["Conflicts"] = debian_pkg_conflicts; } const char* debian_pkg_provides = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PROVIDES"); - if (debian_pkg_provides && *debian_pkg_provides) { + if (cmNonempty(debian_pkg_provides)) { controlValues["Provides"] = debian_pkg_provides; } const char* debian_pkg_replaces = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_REPLACES"); - if (debian_pkg_replaces && *debian_pkg_replaces) { + if (cmNonempty(debian_pkg_replaces)) { controlValues["Replaces"] = debian_pkg_replaces; } @@ -756,7 +756,7 @@ int cmCPackDebGenerator::createDeb() const char* debian_pkg_shlibs = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SHLIBS"); const bool gen_shibs = this->IsOn("CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS") && - debian_pkg_shlibs && *debian_pkg_shlibs; + cmNonempty(debian_pkg_shlibs); if (gen_shibs) { cmGeneratedFileStream out; out.Open(shlibsfilename, false, true); @@ -832,11 +832,11 @@ int cmCPackDebGenerator::createDbgsymDDeb() const char* debian_pkg_source = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE"); - if (debian_pkg_source && *debian_pkg_source) { + if (cmNonempty(debian_pkg_source)) { controlValues["Source"] = debian_pkg_source; } const char* debian_build_ids = this->GetOption("GEN_BUILD_IDS"); - if (debian_build_ids && *debian_build_ids) { + if (cmNonempty(debian_build_ids)) { controlValues["Build-Ids"] = debian_build_ids; } diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx index fe7abf4..cefb906 100644 --- a/Source/CPack/cmCPackDragNDropGenerator.cxx +++ b/Source/CPack/cmCPackDragNDropGenerator.cxx @@ -8,7 +8,9 @@ #include <map> #include <CoreFoundation/CoreFoundation.h> +#include <cm3p/kwiml/abi.h> +#include "cmsys/Base64.h" #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" @@ -18,6 +20,7 @@ #include "cmGeneratedFileStream.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmXMLWriter.h" #ifdef HAVE_CoreServices // For the old LocaleStringToLangAndRegionCodes() function, to convert @@ -26,36 +29,28 @@ # include <CoreServices/CoreServices.h> #endif -static const char* SLAHeader = - "data 'LPic' (5000) {\n" - " $\"0002 0011 0003 0001 0000 0000 0002 0000\"\n" - " $\"0008 0003 0000 0001 0004 0000 0004 0005\"\n" - " $\"0000 000E 0006 0001 0005 0007 0000 0007\"\n" - " $\"0008 0000 0047 0009 0000 0034 000A 0001\"\n" - " $\"0035 000B 0001 0020 000C 0000 0011 000D\"\n" - " $\"0000 005B 0004 0000 0033 000F 0001 000C\"\n" - " $\"0010 0000 000B 000E 0000\"\n" - "};\n" - "\n"; - -static const char* SLASTREnglish = - "resource 'STR#' (5002, \"English\") {\n" - " {\n" - " \"English\",\n" - " \"Agree\",\n" - " \"Disagree\",\n" - " \"Print\",\n" - " \"Save...\",\n" - " \"You agree to the License Agreement terms when you click \"\n" - " \"the \\\"Agree\\\" button.\",\n" - " \"Software License Agreement\",\n" - " \"This text cannot be saved. This disk may be full or locked, " - "or the \"\n" - " \"file may be locked.\",\n" - " \"Unable to print. Make sure you have selected a printer.\"\n" - " }\n" - "};\n" - "\n"; +static const uint16_t DefaultLpic[] = { + /* clang-format off */ + 0x0002, 0x0011, 0x0003, 0x0001, 0x0000, 0x0000, 0x0002, 0x0000, + 0x0008, 0x0003, 0x0000, 0x0001, 0x0004, 0x0000, 0x0004, 0x0005, + 0x0000, 0x000E, 0x0006, 0x0001, 0x0005, 0x0007, 0x0000, 0x0007, + 0x0008, 0x0000, 0x0047, 0x0009, 0x0000, 0x0034, 0x000A, 0x0001, + 0x0035, 0x000B, 0x0001, 0x0020, 0x000C, 0x0000, 0x0011, 0x000D, + 0x0000, 0x005B, 0x0004, 0x0000, 0x0033, 0x000F, 0x0001, 0x000C, + 0x0010, 0x0000, 0x000B, 0x000E, 0x0000 + /* clang-format on */ +}; + +static const std::vector<std::string> DefaultMenu = { + { "English", "Agree", "Disagree", "Print", "Save...", + // NOLINTNEXTLINE(bugprone-suspicious-missing-comma) + "You agree to the License Agreement terms when " + "you click the \"Agree\" button.", + "Software License Agreement", + "This text cannot be saved. " + "This disk may be full or locked, or the file may be locked.", + "Unable to print. Make sure you have selected a printer." } +}; cmCPackDragNDropGenerator::cmCPackDragNDropGenerator() : singleLicense(false) @@ -523,22 +518,43 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, } } + // Create the final compressed read-only disk image ... + std::ostringstream final_image_command; + final_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL"); + final_image_command << " convert \"" << temp_image << "\""; + final_image_command << " -format "; + final_image_command << cpack_dmg_format; + final_image_command << " -imagekey"; + final_image_command << " zlib-level=9"; + final_image_command << " -o \"" << output_file << "\""; + + std::string convert_error; + + if (!this->RunCommand(final_image_command, &convert_error)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error compressing disk image." << std::endl + << convert_error + << std::endl); + + return 0; + } + if (!cpack_license_file.empty() || !slaDirectory.empty()) { // Use old hardcoded style if sla_dir is not set bool oldStyle = slaDirectory.empty(); - std::string sla_r = - cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/sla.r"); + std::string sla_xml = + cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/sla.xml"); std::vector<std::string> languages; if (!oldStyle) { cmExpandList(cpack_dmg_languages, languages); } - cmGeneratedFileStream ofs(sla_r); - ofs << "#include <CoreServices/CoreServices.r>\n\n"; + std::vector<uint16_t> header_data; if (oldStyle) { - ofs << SLAHeader; - ofs << "\n"; + header_data = std::vector<uint16_t>( + DefaultLpic, + DefaultLpic + (sizeof(DefaultLpic) / sizeof(*DefaultLpic))); } else { /* * LPic Layout @@ -558,8 +574,6 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, * } */ - // Create vector first for readability, then iterate to write to ofs - std::vector<uint16_t> header_data; header_data.push_back(0); header_data.push_back(languages.size()); for (size_t i = 0; i < languages.size(); ++i) { @@ -596,52 +610,50 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, header_data.push_back(0); #endif } - ofs << "data 'LPic' (5000) {\n"; - ofs << std::hex << std::uppercase << std::setfill('0'); - - for (size_t i = 0; i < header_data.size(); ++i) { - if (i % 8 == 0) { - ofs << " $\""; - } - - ofs << std::setw(4) << header_data[i]; + } - if (i % 8 == 7 || i == header_data.size() - 1) { - ofs << "\"\n"; - } else { - ofs << " "; - } + RezDoc rez; + + { + RezDict lpic = { {}, 5000, {} }; + lpic.Data.reserve(header_data.size() * sizeof(header_data[0])); + for (uint16_t x : header_data) { + // LPic header is big-endian. + char* d = reinterpret_cast<char*>(&x); +#if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE + lpic.Data.push_back(d[1]); + lpic.Data.push_back(d[0]); +#else + lpic.Data.push_back(d[0]); + lpic.Data.push_back(d[1]); +#endif } - ofs << "};\n\n"; - // Reset ofs options - ofs << std::dec << std::nouppercase << std::setfill(' '); + rez.LPic.Entries.emplace_back(std::move(lpic)); } bool have_write_license_error = false; std::string error; if (oldStyle) { - if (!this->WriteLicense(ofs, 0, "", cpack_license_file, &error)) { + if (!this->WriteLicense(rez, 0, "", cpack_license_file, &error)) { have_write_license_error = true; } } else { for (size_t i = 0; i < languages.size() && !have_write_license_error; ++i) { if (singleLicense) { - if (!this->WriteLicense(ofs, i + 5000, languages[i], + if (!this->WriteLicense(rez, i + 5000, languages[i], cpack_license_file, &error)) { have_write_license_error = true; } } else { - if (!this->WriteLicense(ofs, i + 5000, languages[i], "", &error)) { + if (!this->WriteLicense(rez, i + 5000, languages[i], "", &error)) { have_write_license_error = true; } } } } - ofs.Close(); - if (have_write_license_error) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error writing license file to SLA." << std::endl @@ -650,96 +662,27 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, return 0; } - if (temp_image_format != "UDZO") { - temp_image_format = "UDZO"; - // convert to UDZO to enable unflatten/flatten - std::string temp_udzo = cmStrCat( - this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/temp-udzo.dmg"); + this->WriteRezXML(sla_xml, rez); - std::ostringstream udco_image_command; - udco_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL"); - udco_image_command << " convert \"" << temp_image << "\""; - udco_image_command << " -format UDZO"; - udco_image_command << " -ov -o \"" << temp_udzo << "\""; - - if (!this->RunCommand(udco_image_command, &error)) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error converting to UDCO dmg for adding SLA." - << std::endl - << error << std::endl); - return 0; - } - temp_image = temp_udzo; - } - - // unflatten dmg - std::ostringstream unflatten_command; - unflatten_command << this->GetOption("CPACK_COMMAND_HDIUTIL"); - unflatten_command << " unflatten "; - unflatten_command << "\"" << temp_image << "\""; - - if (!this->RunCommand(unflatten_command, &error)) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error unflattening dmg for adding SLA." << std::endl - << error - << std::endl); - return 0; - } - - // Rez the SLA + // Create the final compressed read-only disk image ... std::ostringstream embed_sla_command; - embed_sla_command << this->GetOption("CPACK_COMMAND_REZ"); - const char* sysroot = this->GetOption("CPACK_OSX_SYSROOT"); - if (sysroot && sysroot[0] != '\0') { - embed_sla_command << " -isysroot \"" << sysroot << "\""; - } - embed_sla_command << " \"" << sla_r << "\""; - embed_sla_command << " -a -o "; - embed_sla_command << "\"" << temp_image << "\""; - - if (!this->RunCommand(embed_sla_command, &error)) { + embed_sla_command << this->GetOption("CPACK_COMMAND_HDIUTIL"); + embed_sla_command << " udifrez"; + embed_sla_command << " -xml"; + embed_sla_command << " \"" << sla_xml << "\""; + embed_sla_command << " FIXME_WHY_IS_THIS_ARGUMENT_NEEDED"; + embed_sla_command << " \"" << output_file << "\""; + std::string embed_error; + if (!this->RunCommand(embed_sla_command, &embed_error)) { cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error adding SLA." << std::endl - << error << std::endl); - return 0; - } - - // flatten dmg - std::ostringstream flatten_command; - flatten_command << this->GetOption("CPACK_COMMAND_HDIUTIL"); - flatten_command << " flatten "; - flatten_command << "\"" << temp_image << "\""; + "Error compressing disk image." << std::endl + << embed_error + << std::endl); - if (!this->RunCommand(flatten_command, &error)) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error flattening dmg for adding SLA." << std::endl - << error - << std::endl); return 0; } } - // Create the final compressed read-only disk image ... - std::ostringstream final_image_command; - final_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL"); - final_image_command << " convert \"" << temp_image << "\""; - final_image_command << " -format "; - final_image_command << cpack_dmg_format; - final_image_command << " -imagekey"; - final_image_command << " zlib-level=9"; - final_image_command << " -o \"" << output_file << "\""; - - std::string convert_error; - - if (!this->RunCommand(final_image_command, &convert_error)) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error compressing disk image." << std::endl - << convert_error - << std::endl); - - return 0; - } - return 1; } @@ -788,10 +731,67 @@ std::string cmCPackDragNDropGenerator::GetComponentInstallDirNameSuffix( return GetComponentPackageFileName(package_file_name, componentName, false); } -bool cmCPackDragNDropGenerator::WriteLicense( - cmGeneratedFileStream& outputStream, int licenseNumber, - std::string licenseLanguage, const std::string& licenseFile, - std::string* error) +void cmCPackDragNDropGenerator::WriteRezXML(std::string const& file, + RezDoc const& rez) +{ + cmGeneratedFileStream fxml(file); + cmXMLWriter xml(fxml); + xml.StartDocument(); + xml.StartElement("plist"); + xml.Attribute("version", "1.0"); + xml.StartElement("dict"); + this->WriteRezArray(xml, rez.LPic); + this->WriteRezArray(xml, rez.Menu); + this->WriteRezArray(xml, rez.Text); + this->WriteRezArray(xml, rez.RTF); + xml.EndElement(); // dict + xml.EndElement(); // plist + xml.EndDocument(); + fxml.Close(); +} + +void cmCPackDragNDropGenerator::WriteRezArray(cmXMLWriter& xml, + RezArray const& array) +{ + if (array.Entries.empty()) { + return; + } + xml.StartElement("key"); + xml.Content(array.Key); + xml.EndElement(); // key + xml.StartElement("array"); + for (RezDict const& dict : array.Entries) { + this->WriteRezDict(xml, dict); + } + xml.EndElement(); // array +} + +void cmCPackDragNDropGenerator::WriteRezDict(cmXMLWriter& xml, + RezDict const& dict) +{ + std::vector<char> base64buf(dict.Data.size() * 3 / 2 + 5); + size_t base64len = + cmsysBase64_Encode(dict.Data.data(), dict.Data.size(), + reinterpret_cast<unsigned char*>(base64buf.data()), 0); + std::string base64data(base64buf.data(), base64len); + /* clang-format off */ + xml.StartElement("dict"); + xml.StartElement("key"); xml.Content("Attributes"); xml.EndElement(); + xml.StartElement("string"); xml.Content("0x0000"); xml.EndElement(); + xml.StartElement("key"); xml.Content("Data"); xml.EndElement(); + xml.StartElement("data"); xml.Content(base64data); xml.EndElement(); + xml.StartElement("key"); xml.Content("ID"); xml.EndElement(); + xml.StartElement("string"); xml.Content(dict.ID); xml.EndElement(); + xml.StartElement("key"); xml.Content("Name"); xml.EndElement(); + xml.StartElement("string"); xml.Content(dict.Name); xml.EndElement(); + xml.EndElement(); // dict + /* clang-format on */ +} + +bool cmCPackDragNDropGenerator::WriteLicense(RezDoc& rez, size_t licenseNumber, + std::string licenseLanguage, + const std::string& licenseFile, + std::string* error) { if (!licenseFile.empty() && !singleLicense) { licenseNumber = 5002; @@ -799,11 +799,11 @@ bool cmCPackDragNDropGenerator::WriteLicense( } // License file - std::string license_format = "TEXT"; + RezArray* licenseArray = &rez.Text; std::string actual_license; if (!licenseFile.empty()) { if (cmHasLiteralSuffix(licenseFile, ".rtf")) { - license_format = "RTF "; + licenseArray = &rez.RTF; } actual_license = licenseFile; } else { @@ -812,85 +812,86 @@ bool cmCPackDragNDropGenerator::WriteLicense( if (cmSystemTools::FileExists(license_wo_ext + ".txt")) { actual_license = license_wo_ext + ".txt"; } else { - license_format = "RTF "; + licenseArray = &rez.RTF; actual_license = license_wo_ext + ".rtf"; } } - // License header - outputStream << "data '" << license_format << "' (" << licenseNumber - << ", \"" << licenseLanguage << "\") {\n"; // License body - cmsys::ifstream license_ifs; - license_ifs.open(actual_license.c_str()); - if (license_ifs.is_open()) { - while (license_ifs.good()) { - std::string line; - std::getline(license_ifs, line); - if (!line.empty()) { - EscapeQuotesAndBackslashes(line); - std::vector<std::string> lines; - if (!this->BreakLongLine(line, lines, error)) { - return false; - } - for (auto const& l : lines) { - outputStream << " \"" << l << "\"\n"; - } - } - outputStream << " \"\\n\"\n"; + { + RezDict license = { licenseLanguage, licenseNumber, {} }; + std::vector<std::string> lines; + if (!this->ReadFile(actual_license, lines, error)) { + return false; } - license_ifs.close(); + this->EncodeLicense(license, lines); + licenseArray->Entries.emplace_back(std::move(license)); } - // End of License - outputStream << "};\n\n"; - if (!licenseFile.empty() && !singleLicense) { - outputStream << SLASTREnglish; - } else { - // Menu header - outputStream << "resource 'STR#' (" << licenseNumber << ", \"" - << licenseLanguage << "\") {\n"; - outputStream << " {\n"; - - // Menu body - cmsys::ifstream menu_ifs; - menu_ifs.open( - (slaDirectory + "/" + licenseLanguage + ".menu.txt").c_str()); - if (menu_ifs.is_open()) { - size_t lines_written = 0; - while (menu_ifs.good()) { - // Lines written from original file, not from broken up lines - std::string line; - std::getline(menu_ifs, line); - if (!line.empty()) { - EscapeQuotesAndBackslashes(line); - std::vector<std::string> lines; - if (!this->BreakLongLine(line, lines, error)) { - return false; - } - for (size_t i = 0; i < lines.size(); ++i) { - std::string comma; - // We need a comma after every complete string, - // but not on the very last line - if (lines_written != 8 && i == lines.size() - 1) { - comma = ","; - } else { - comma = ""; - } - outputStream << " \"" << lines[i] << "\"" << comma << "\n"; - } - ++lines_written; - } + // Menu body + { + RezDict menu = { licenseLanguage, licenseNumber, {} }; + if (!licenseFile.empty() && !singleLicense) { + this->EncodeMenu(menu, DefaultMenu); + } else { + std::vector<std::string> lines; + std::string actual_menu = + slaDirectory + "/" + licenseLanguage + ".menu.txt"; + if (!this->ReadFile(actual_menu, lines, error)) { + return false; } - menu_ifs.close(); + this->EncodeMenu(menu, lines); } + rez.Menu.Entries.emplace_back(std::move(menu)); + } + + return true; +} + +void cmCPackDragNDropGenerator::EncodeLicense( + RezDict& dict, std::vector<std::string> const& lines) +{ + // License text uses CR newlines. + for (std::string const& l : lines) { + dict.Data.insert(dict.Data.end(), l.begin(), l.end()); + dict.Data.push_back('\r'); + } + dict.Data.push_back('\r'); +} - // End of menu - outputStream << " }\n"; - outputStream << "};\n"; - outputStream << "\n"; +void cmCPackDragNDropGenerator::EncodeMenu( + RezDict& dict, std::vector<std::string> const& lines) +{ + // Menu resources start with a big-endian uint16_t for number of lines: + { + uint16_t numLines = static_cast<uint16_t>(lines.size()); + char* d = reinterpret_cast<char*>(&numLines); +#if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE + dict.Data.push_back(d[1]); + dict.Data.push_back(d[0]); +#else + dict.Data.push_back(d[0]); + dict.Data.push_back(d[1]); +#endif } + // Each line starts with a uint8_t length, plus the bytes themselves: + for (std::string const& l : lines) { + dict.Data.push_back(static_cast<unsigned char>(l.length())); + dict.Data.insert(dict.Data.end(), l.begin(), l.end()); + } +} +bool cmCPackDragNDropGenerator::ReadFile(std::string const& file, + std::vector<std::string>& lines, + std::string* error) +{ + cmsys::ifstream ifs(file); + std::string line; + while (std::getline(ifs, line)) { + if (!this->BreakLongLine(line, lines, error)) { + return false; + } + } return true; } @@ -898,7 +899,7 @@ bool cmCPackDragNDropGenerator::BreakLongLine(const std::string& line, std::vector<std::string>& lines, std::string* error) { - const size_t max_line_length = 512; + const size_t max_line_length = 255; size_t line_length = max_line_length; for (size_t i = 0; i < line.size(); i += line_length) { line_length = max_line_length; @@ -913,25 +914,10 @@ bool cmCPackDragNDropGenerator::BreakLongLine(const std::string& line, if (line_length == 0) { *error = "Please make sure there are no words " "(or character sequences not broken up by spaces or newlines) " - "in your license file which are more than 512 characters long."; + "in your license file which are more than 255 characters long."; return false; } lines.push_back(line.substr(i, line_length)); } return true; } - -void cmCPackDragNDropGenerator::EscapeQuotesAndBackslashes(std::string& line) -{ - std::string::size_type backslash_pos = line.find('\\'); - while (backslash_pos != std::string::npos) { - line.replace(backslash_pos, 1, "\\\\"); - backslash_pos = line.find('\\', backslash_pos + 2); - } - - std::string::size_type quote_pos = line.find('\"'); - while (quote_pos != std::string::npos) { - line.replace(quote_pos, 1, "\\\""); - quote_pos = line.find('\"', quote_pos + 2); - } -} diff --git a/Source/CPack/cmCPackDragNDropGenerator.h b/Source/CPack/cmCPackDragNDropGenerator.h index f8c86c0..dbd190c 100644 --- a/Source/CPack/cmCPackDragNDropGenerator.h +++ b/Source/CPack/cmCPackDragNDropGenerator.h @@ -14,6 +14,7 @@ #include "cmCPackGenerator.h" class cmGeneratedFileStream; +class cmXMLWriter; /** \class cmCPackDragNDropGenerator * \brief A generator for OSX drag-n-drop installs @@ -45,12 +46,40 @@ private: std::string slaDirectory; bool singleLicense; - bool WriteLicense(cmGeneratedFileStream& outputStream, int licenseNumber, + struct RezDict + { + std::string Name; + size_t ID; + std::vector<unsigned char> Data; + }; + + struct RezArray + { + std::string Key; + std::vector<RezDict> Entries; + }; + + struct RezDoc + { + RezArray LPic = { "LPic", {} }; + RezArray Menu = { "STR#", {} }; + RezArray Text = { "TEXT", {} }; + RezArray RTF = { "RTF ", {} }; + }; + + void WriteRezXML(std::string const& file, RezDoc const& rez); + void WriteRezArray(cmXMLWriter& xml, RezArray const& array); + void WriteRezDict(cmXMLWriter& xml, RezDict const& dict); + + bool WriteLicense(RezDoc& rez, size_t licenseNumber, std::string licenseLanguage, const std::string& licenseFile, std::string* error); + void EncodeLicense(RezDict& dict, std::vector<std::string> const& lines); + void EncodeMenu(RezDict& dict, std::vector<std::string> const& lines); + bool ReadFile(std::string const& file, std::vector<std::string>& lines, + std::string* error); bool BreakLongLine(const std::string& line, std::vector<std::string>& lines, std::string* error); - void EscapeQuotesAndBackslashes(std::string& line); }; #endif diff --git a/Source/CPack/cmCPackExternalGenerator.cxx b/Source/CPack/cmCPackExternalGenerator.cxx index 11e1aec..0bc8456 100644 --- a/Source/CPack/cmCPackExternalGenerator.cxx +++ b/Source/CPack/cmCPackExternalGenerator.cxx @@ -61,7 +61,7 @@ int cmCPackExternalGenerator::PackageFiles() } const char* packageScript = this->GetOption("CPACK_EXTERNAL_PACKAGE_SCRIPT"); - if (packageScript && *packageScript) { + if (cmNonempty(packageScript)) { if (!cmSystemTools::FileIsFullPath(packageScript)) { cmCPackLogger( cmCPackLog::LOG_ERROR, @@ -75,6 +75,12 @@ int cmCPackExternalGenerator::PackageFiles() if (cmSystemTools::GetErrorOccuredFlag() || !res) { return 0; } + + const char* builtPackagesStr = + this->GetOption("CPACK_EXTERNAL_BUILT_PACKAGES"); + if (builtPackagesStr) { + cmExpandList(builtPackagesStr, this->packageFileNames, false); + } } return 1; @@ -205,7 +211,7 @@ int cmCPackExternalGenerator::cmCPackExternalVersionGenerator::WriteToJSON( const char* defaultDirectoryPermissions = this->Parent->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS"); - if (defaultDirectoryPermissions && *defaultDirectoryPermissions) { + if (cmNonempty(defaultDirectoryPermissions)) { root["defaultDirectoryPermissions"] = defaultDirectoryPermissions; } if (cmIsInternallyOn(this->Parent->GetOption("CPACK_SET_DESTDIR"))) { diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index 288dc58..3880f65 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -216,7 +216,7 @@ int cmCPackGenerator::InstallProject() mode_t* default_dir_mode = nullptr; const char* default_dir_install_permissions = this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS"); - if (default_dir_install_permissions && *default_dir_install_permissions) { + if (cmNonempty(default_dir_install_permissions)) { std::vector<std::string> items = cmExpandedList(default_dir_install_permissions); for (const auto& arg : items) { @@ -264,6 +264,23 @@ int cmCPackGenerator::InstallProject() return 0; } + // Run pre-build actions + const char* preBuildScripts = this->GetOption("CPACK_PRE_BUILD_SCRIPTS"); + if (preBuildScripts) { + const auto scripts = cmExpandedList(preBuildScripts, false); + for (const auto& script : scripts) { + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "Executing pre-build script: " << script << std::endl); + + if (!this->MakefileMap->ReadListFile(script)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "The pre-build script not found: " << script + << std::endl); + return 0; + } + } + } + if (setDestDir) { cmSystemTools::PutEnv("DESTDIR="); } @@ -276,7 +293,7 @@ int cmCPackGenerator::InstallProjectViaInstallCommands( { (void)setDestDir; const char* installCommands = this->GetOption("CPACK_INSTALL_COMMANDS"); - if (installCommands && *installCommands) { + if (cmNonempty(installCommands)) { std::string tempInstallDirectoryEnv = cmStrCat("CMAKE_INSTALL_PREFIX=", tempInstallDirectory); cmSystemTools::PutEnv(tempInstallDirectoryEnv); @@ -327,13 +344,14 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( } const char* installDirectories = this->GetOption("CPACK_INSTALLED_DIRECTORIES"); - if (installDirectories && *installDirectories) { + if (cmNonempty(installDirectories)) { std::vector<std::string> installDirectoriesVector = cmExpandedList(installDirectories); if (installDirectoriesVector.size() % 2 != 0) { cmCPackLogger( cmCPackLog::LOG_ERROR, - "CPACK_INSTALLED_DIRECTORIES should contain pairs of <directory> and " + "CPACK_INSTALLED_DIRECTORIES should contain pairs of <directory> " + "and " "<subdirectory>. The <subdirectory> can be '.' to be installed in " "the toplevel directory of installation." << std::endl); @@ -475,10 +493,10 @@ int cmCPackGenerator::InstallProjectViaInstallScript( "- Install script: " << installScript << std::endl); if (setDestDir) { - // For DESTDIR based packaging, use the *project* CMAKE_INSTALL_PREFIX - // underneath the tempInstallDirectory. The value of the project's - // CMAKE_INSTALL_PREFIX is sent in here as the value of the - // CPACK_INSTALL_PREFIX variable. + // For DESTDIR based packaging, use the *project* + // CMAKE_INSTALL_PREFIX underneath the tempInstallDirectory. The + // value of the project's CMAKE_INSTALL_PREFIX is sent in here as the + // value of the CPACK_INSTALL_PREFIX variable. std::string dir; if (this->GetOption("CPACK_INSTALL_PREFIX")) { @@ -523,7 +541,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( const char* cmakeProjects = this->GetOption("CPACK_INSTALL_CMAKE_PROJECTS"); const char* cmakeGenerator = this->GetOption("CPACK_CMAKE_GENERATOR"); std::string absoluteDestFiles; - if (cmakeProjects && *cmakeProjects) { + if (cmNonempty(cmakeProjects)) { if (!cmakeGenerator) { cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_INSTALL_CMAKE_PROJECTS is specified, but " @@ -576,7 +594,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( std::string installTypesVar = "CPACK_" + cmSystemTools::UpperCase(project.Component) + "_INSTALL_TYPES"; const char* installTypes = this->GetOption(installTypesVar); - if (installTypes && *installTypes) { + if (cmNonempty(installTypes)) { std::vector<std::string> installTypesVector = cmExpandedList(installTypes); for (std::string const& installType : installTypesVector) { @@ -589,7 +607,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( std::string componentsVar = "CPACK_COMPONENTS_" + cmSystemTools::UpperCase(project.Component); const char* components = this->GetOption(componentsVar); - if (components && *components) { + if (cmNonempty(components)) { cmExpandList(components, componentsVector); for (std::string const& comp : componentsVector) { project.Components.push_back( @@ -753,7 +771,7 @@ int cmCPackGenerator::InstallCMakeProject( const char* default_dir_inst_permissions = this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS"); - if (default_dir_inst_permissions && *default_dir_inst_permissions) { + if (cmNonempty(default_dir_inst_permissions)) { mf.AddDefinition("CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS", default_dir_inst_permissions); } @@ -811,7 +829,7 @@ int cmCPackGenerator::InstallCMakeProject( * - Because it was already used for component install * in order to put things in subdirs... */ - cmSystemTools::PutEnv(std::string("DESTDIR=") + tempInstallDirectory); + cmSystemTools::PutEnv("DESTDIR=" + tempInstallDirectory); cmCPackLogger(cmCPackLog::LOG_DEBUG, "- Creating directory: '" << dir << "'" << std::endl); @@ -965,7 +983,7 @@ void cmCPackGenerator::SetOptionIfNotSet(const std::string& op, const char* value) { const char* def = this->MakefileMap->GetDefinition(op); - if (def && *def) { + if (cmNonempty(def)) { return; } this->SetOption(op, value); @@ -1076,6 +1094,25 @@ int cmCPackGenerator::DoPackage() return 0; } } + // Run post-build actions + const char* postBuildScripts = this->GetOption("CPACK_POST_BUILD_SCRIPTS"); + if (postBuildScripts) { + this->MakefileMap->AddDefinition("CPACK_PACKAGE_FILES", + cmJoin(this->packageFileNames, ";")); + + const auto scripts = cmExpandedList(postBuildScripts, false); + for (const auto& script : scripts) { + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "Executing post-build script: " << script << std::endl); + + if (!this->MakefileMap->ReadListFile(script)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "The post-build script not found: " << script + << std::endl); + return 0; + } + } + } /* Prepare checksum algorithm*/ const char* algo = this->GetOption("CPACK_PACKAGE_CHECKSUM"); @@ -1178,7 +1215,7 @@ bool cmCPackGenerator::IsOn(const std::string& name) const bool cmCPackGenerator::IsSetToOff(const std::string& op) const { const char* ret = this->MakefileMap->GetDefinition(op); - if (ret && *ret) { + if (cmNonempty(ret)) { return cmIsOff(ret); } return false; @@ -1289,7 +1326,7 @@ bool cmCPackGenerator::ConfigureFile(const std::string& inName, bool copyOnly /* = false */) { return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true, - false) == 1; + false, true) == 1; } int cmCPackGenerator::CleanTemporaryDirectory() @@ -1378,7 +1415,8 @@ int cmCPackGenerator::PrepareGroupingKind() << std::endl); } - // if user specified packaging method, override the default packaging method + // if user specified packaging method, override the default packaging + // method if (method != UNKNOWN_COMPONENT_PACKAGE_METHOD) { componentPackageMethod = method; } @@ -1471,7 +1509,7 @@ cmCPackInstallationType* cmCPackGenerator::GetInstallationType( installType->Name = name; const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME"); - if (displayName && *displayName) { + if (cmNonempty(displayName)) { installType->DisplayName = displayName; } else { installType->DisplayName = installType->Name; @@ -1493,7 +1531,7 @@ cmCPackComponent* cmCPackGenerator::GetComponent( "CPACK_COMPONENT_" + cmsys::SystemTools::UpperCase(name); component->Name = name; const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME"); - if (displayName && *displayName) { + if (cmNonempty(displayName)) { component->DisplayName = displayName; } else { component->DisplayName = component->Name; @@ -1505,17 +1543,17 @@ cmCPackComponent* cmCPackGenerator::GetComponent( cmIsOn(this->GetOption("CPACK_DOWNLOAD_ALL")); const char* archiveFile = this->GetOption(macroPrefix + "_ARCHIVE_FILE"); - if (archiveFile && *archiveFile) { + if (cmNonempty(archiveFile)) { component->ArchiveFile = archiveFile; } const char* plist = this->GetOption(macroPrefix + "_PLIST"); - if (plist && *plist) { + if (cmNonempty(plist)) { component->Plist = plist; } const char* groupName = this->GetOption(macroPrefix + "_GROUP"); - if (groupName && *groupName) { + if (cmNonempty(groupName)) { component->Group = GetComponentGroup(projectName, groupName); component->Group->Components.push_back(component); } else { @@ -1523,13 +1561,13 @@ cmCPackComponent* cmCPackGenerator::GetComponent( } const char* description = this->GetOption(macroPrefix + "_DESCRIPTION"); - if (description && *description) { + if (cmNonempty(description)) { component->Description = description; } // Determine the installation types. const char* installTypes = this->GetOption(macroPrefix + "_INSTALL_TYPES"); - if (installTypes && *installTypes) { + if (cmNonempty(installTypes)) { std::vector<std::string> installTypesVector = cmExpandedList(installTypes); for (std::string const& installType : installTypesVector) { @@ -1540,7 +1578,7 @@ cmCPackComponent* cmCPackGenerator::GetComponent( // Determine the component dependencies. const char* depends = this->GetOption(macroPrefix + "_DEPENDS"); - if (depends && *depends) { + if (cmNonempty(depends)) { std::vector<std::string> dependsVector = cmExpandedList(depends); for (std::string const& depend : dependsVector) { cmCPackComponent* child = GetComponent(projectName, depend); @@ -1564,21 +1602,21 @@ cmCPackComponentGroup* cmCPackGenerator::GetComponentGroup( // Define the group group->Name = name; const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME"); - if (displayName && *displayName) { + if (cmNonempty(displayName)) { group->DisplayName = displayName; } else { group->DisplayName = group->Name; } const char* description = this->GetOption(macroPrefix + "_DESCRIPTION"); - if (description && *description) { + if (cmNonempty(description)) { group->Description = description; } group->IsBold = this->IsOn(macroPrefix + "_BOLD_TITLE"); group->IsExpandedByDefault = this->IsOn(macroPrefix + "_EXPANDED"); const char* parentGroupName = this->GetOption(macroPrefix + "_PARENT_GROUP"); - if (parentGroupName && *parentGroupName) { + if (cmNonempty(parentGroupName)) { group->ParentGroup = GetComponentGroup(projectName, parentGroupName); group->ParentGroup->Subgroups.push_back(group); } else { diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx index 058b090..2109b4e 100644 --- a/Source/CPack/cmCPackNSISGenerator.cxx +++ b/Source/CPack/cmCPackNSISGenerator.cxx @@ -696,7 +696,7 @@ std::string cmCPackNSISGenerator::CreateComponentDescription( const char* userUploadDirectory = this->GetOption("CPACK_UPLOAD_DIRECTORY"); std::string uploadDirectory; - if (userUploadDirectory && *userUploadDirectory) { + if (cmNonempty(userUploadDirectory)) { uploadDirectory = userUploadDirectory; } else { uploadDirectory = diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index db426b2..a18cbb4 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -182,10 +182,9 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) std::vector<std::string> extraPaths; std::vector<std::string> failed; fullPath = cmCTestTestHandler::FindExecutable( - this->CTest, this->ConfigSample.c_str(), resultingConfig, extraPaths, - failed); + this->CTest, this->ConfigSample, resultingConfig, extraPaths, failed); if (!fullPath.empty() && !resultingConfig.empty()) { - this->CTest->SetConfigType(resultingConfig.c_str()); + this->CTest->SetConfigType(resultingConfig); } out << "Using config sample with results: " << fullPath << " and " << resultingConfig << std::endl; @@ -296,9 +295,8 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) extraPaths.push_back(tempPath); } std::vector<std::string> failed; - fullPath = - cmCTestTestHandler::FindExecutable(this->CTest, this->TestCommand.c_str(), - resultingConfig, extraPaths, failed); + fullPath = cmCTestTestHandler::FindExecutable( + this->CTest, this->TestCommand, resultingConfig, extraPaths, failed); if (!cmSystemTools::FileExists(fullPath)) { out << "Could not find path to executable, perhaps it was not built: " diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx index 44fdc29..8aab167 100644 --- a/Source/CTest/cmCTestBuildCommand.cxx +++ b/Source/CTest/cmCTestBuildCommand.cxx @@ -12,6 +12,7 @@ #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmProperty.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmake.h" @@ -38,10 +39,9 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() this->Handler = handler; - const char* ctestBuildCommand = - this->Makefile->GetDefinition("CTEST_BUILD_COMMAND"); - if (ctestBuildCommand && *ctestBuildCommand) { - this->CTest->SetCTestConfiguration("MakeCommand", ctestBuildCommand, + cmProp ctestBuildCommand = this->Makefile->GetDef("CTEST_BUILD_COMMAND"); + if (cmNonempty(ctestBuildCommand)) { + this->CTest->SetCTestConfiguration("MakeCommand", *ctestBuildCommand, this->Quiet); } else { const char* cmakeGeneratorName = @@ -56,7 +56,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION"); const char* cmakeBuildConfiguration = !this->Configuration.empty() ? this->Configuration.c_str() - : ((ctestBuildConfiguration && *ctestBuildConfiguration) + : (cmNonempty(ctestBuildConfiguration) ? ctestBuildConfiguration : this->CTest->GetConfigType().c_str()); @@ -67,7 +67,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() ? this->Target.c_str() : this->Makefile->GetDefinition("CTEST_BUILD_TARGET"); - if (cmakeGeneratorName && *cmakeGeneratorName) { + if (cmNonempty(cmakeGeneratorName)) { if (!cmakeBuildConfiguration) { cmakeBuildConfiguration = "Release"; } @@ -108,7 +108,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "SetMakeCommand:" << buildCommand << "\n", this->Quiet); - this->CTest->SetCTestConfiguration("MakeCommand", buildCommand.c_str(), + this->CTest->SetCTestConfiguration("MakeCommand", buildCommand, this->Quiet); } else { std::ostringstream ostr; @@ -123,16 +123,15 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() } } - if (const char* useLaunchers = - this->Makefile->GetDefinition("CTEST_USE_LAUNCHERS")) { - this->CTest->SetCTestConfiguration("UseLaunchers", useLaunchers, + if (cmProp useLaunchers = this->Makefile->GetDef("CTEST_USE_LAUNCHERS")) { + this->CTest->SetCTestConfiguration("UseLaunchers", *useLaunchers, this->Quiet); } - if (const char* labelsForSubprojects = - this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) { + if (cmProp labelsForSubprojects = + this->Makefile->GetDef("CTEST_LABELS_FOR_SUBPROJECTS")) { this->CTest->SetCTestConfiguration("LabelsForSubprojects", - labelsForSubprojects, this->Quiet); + *labelsForSubprojects, this->Quiet); } handler->SetQuiet(this->Quiet); diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx index f42c3f1..ac57130 100644 --- a/Source/CTest/cmCTestConfigureCommand.cxx +++ b/Source/CTest/cmCTestConfigureCommand.cxx @@ -12,6 +12,7 @@ #include "cmCTestConfigureHandler.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmake.h" @@ -38,16 +39,16 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() return nullptr; } - const char* ctestConfigureCommand = - this->Makefile->GetDefinition("CTEST_CONFIGURE_COMMAND"); + cmProp ctestConfigureCommand = + this->Makefile->GetDef("CTEST_CONFIGURE_COMMAND"); - if (ctestConfigureCommand && *ctestConfigureCommand) { + if (cmNonempty(ctestConfigureCommand)) { this->CTest->SetCTestConfiguration("ConfigureCommand", - ctestConfigureCommand, this->Quiet); + *ctestConfigureCommand, this->Quiet); } else { const char* cmakeGeneratorName = this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR"); - if (cmakeGeneratorName && *cmakeGeneratorName) { + if (cmNonempty(cmakeGeneratorName)) { const std::string& source_dir = this->CTest->GetCTestConfiguration("SourceDirectory"); if (source_dir.empty()) { @@ -107,7 +108,7 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() const char* cmakeGeneratorPlatform = this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_PLATFORM"); - if (cmakeGeneratorPlatform && *cmakeGeneratorPlatform) { + if (cmNonempty(cmakeGeneratorPlatform)) { cmakeConfigureCommand += " \"-A"; cmakeConfigureCommand += cmakeGeneratorPlatform; cmakeConfigureCommand += "\""; @@ -115,7 +116,7 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() const char* cmakeGeneratorToolset = this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_TOOLSET"); - if (cmakeGeneratorToolset && *cmakeGeneratorToolset) { + if (cmNonempty(cmakeGeneratorToolset)) { cmakeConfigureCommand += " \"-T"; cmakeConfigureCommand += cmakeGeneratorToolset; cmakeConfigureCommand += "\""; @@ -125,8 +126,8 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() cmakeConfigureCommand += source_dir; cmakeConfigureCommand += "\""; - this->CTest->SetCTestConfiguration( - "ConfigureCommand", cmakeConfigureCommand.c_str(), this->Quiet); + this->CTest->SetCTestConfiguration("ConfigureCommand", + cmakeConfigureCommand, this->Quiet); } else { this->SetError( "Configure command is not specified. If this is a " @@ -136,10 +137,10 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() } } - if (const char* labelsForSubprojects = - this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) { + if (cmProp labelsForSubprojects = + this->Makefile->GetDef("CTEST_LABELS_FOR_SUBPROJECTS")) { this->CTest->SetCTestConfiguration("LabelsForSubprojects", - labelsForSubprojects, this->Quiet); + *labelsForSubprojects, this->Quiet); } cmCTestConfigureHandler* handler = this->CTest->GetConfigureHandler(); diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index b839c10..093b2d1 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -469,8 +469,8 @@ int cmCTestCoverageHandler::ProcessHandler() } const std::string fileName = cmSystemTools::GetFilenameName(fullFileName); - std::string shortFileName = - this->CTest->GetShortPathToFile(fullFileName.c_str()); + const std::string shortFileName = + this->CTest->GetShortPathToFile(fullFileName); const cmCTestCoverageHandlerContainer::SingleFileCoverageVector& fcov = file.second; covLogXML.StartElement("File"); @@ -538,7 +538,7 @@ int cmCTestCoverageHandler::ProcessHandler() covSumXML.StartElement("File"); covSumXML.Attribute("Name", fileName); covSumXML.Attribute("FullPath", - this->CTest->GetShortPathToFile(fullFileName.c_str())); + this->CTest->GetShortPathToFile(fullFileName)); covSumXML.Attribute("Covered", tested + untested > 0 ? "true" : "false"); covSumXML.Element("LOCTested", tested); covSumXML.Element("LOCUnTested", untested); @@ -1887,8 +1887,8 @@ int cmCTestCoverageHandler::RunBullseyeCoverageBranch( // start the file output covLogXML.StartElement("File"); covLogXML.Attribute("Name", i->first); - covLogXML.Attribute( - "FullPath", this->CTest->GetShortPathToFile(i->second.c_str())); + covLogXML.Attribute("FullPath", + this->CTest->GetShortPathToFile(i->second)); covLogXML.StartElement("Report"); // write the bullseye header line = 0; @@ -2064,8 +2064,7 @@ int cmCTestCoverageHandler::RunBullseyeSourceSummary( total_untested += (totalFunctions - functionsCalled); std::string fileName = cmSystemTools::GetFilenameName(file); - std::string shortFileName = - this->CTest->GetShortPathToFile(file.c_str()); + std::string shortFileName = this->CTest->GetShortPathToFile(file); float cper = static_cast<float>(percentBranch + percentFunction); if (totalBranches > 0) { @@ -2266,7 +2265,7 @@ void cmCTestCoverageHandler::LoadLabels(const char* dir) // is the end of the target-wide labels. inTarget = false; - source = this->CTest->GetShortPathToFile(line.c_str()); + source = this->CTest->GetShortPathToFile(line); // Label the source with the target labels. LabelSet& labelSet = this->SourceLabels[source]; @@ -2320,7 +2319,7 @@ bool cmCTestCoverageHandler::IsFilteredOut(std::string const& source) // The source is filtered out if it does not have any labels in // common with the filter set. - std::string shortSrc = this->CTest->GetShortPathToFile(source.c_str()); + std::string shortSrc = this->CTest->GetShortPathToFile(source); auto li = this->SourceLabels.find(shortSrc); if (li != this->SourceLabels.end()) { return !this->IntersectsFilter(li->second); @@ -2342,14 +2341,14 @@ std::set<std::string> cmCTestCoverageHandler::FindUncoveredFiles( std::vector<std::string> files = gl.GetFiles(); for (std::string const& f : files) { if (this->ShouldIDoCoverage(f, cont->SourceDir, cont->BinaryDir)) { - extraMatches.insert(this->CTest->GetShortPathToFile(f.c_str())); + extraMatches.insert(this->CTest->GetShortPathToFile(f)); } } } if (!extraMatches.empty()) { for (auto const& i : cont->TotalCoverage) { - std::string shortPath = this->CTest->GetShortPathToFile(i.first.c_str()); + std::string shortPath = this->CTest->GetShortPathToFile(i.first); extraMatches.erase(shortPath); } } diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx index cc0b4ed..a71f550 100644 --- a/Source/CTest/cmCTestGenericHandler.cxx +++ b/Source/CTest/cmCTestGenericHandler.cxx @@ -100,7 +100,7 @@ bool cmCTestGenericHandler::StartResultingXML(cmCTest::Part part, << std::endl); return false; } - this->CTest->AddSubmitFile(part, ostr.str().c_str()); + this->CTest->AddSubmitFile(part, ostr.str()); return true; } diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index a755632..03b7173 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -14,6 +14,7 @@ #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmProperty.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmWorkingDirectory.h" @@ -125,23 +126,21 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, // CTEST_CONFIGURATION_TYPE script variable if it is defined. // The current script value trumps the -C argument on the command // line. - const char* ctestConfigType = - this->Makefile->GetDefinition("CTEST_CONFIGURATION_TYPE"); + cmProp ctestConfigType = this->Makefile->GetDef("CTEST_CONFIGURATION_TYPE"); if (ctestConfigType) { - this->CTest->SetConfigType(ctestConfigType); + this->CTest->SetConfigType(*ctestConfigType); } if (!this->Build.empty()) { this->CTest->SetCTestConfiguration( - "BuildDirectory", cmSystemTools::CollapseFullPath(this->Build).c_str(), + "BuildDirectory", cmSystemTools::CollapseFullPath(this->Build), this->Quiet); } else { std::string const& bdir = this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY"); if (!bdir.empty()) { this->CTest->SetCTestConfiguration( - "BuildDirectory", cmSystemTools::CollapseFullPath(bdir).c_str(), - this->Quiet); + "BuildDirectory", cmSystemTools::CollapseFullPath(bdir), this->Quiet); } else { cmCTestLog(this->CTest, ERROR_MESSAGE, "CTEST_BINARY_DIRECTORY not set" << std::endl;); @@ -151,20 +150,18 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, cmCTestLog(this->CTest, DEBUG, "Set source directory to: " << this->Source << std::endl); this->CTest->SetCTestConfiguration( - "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source).c_str(), + "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source), this->Quiet); } else { this->CTest->SetCTestConfiguration( "SourceDirectory", cmSystemTools::CollapseFullPath( - this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")) - .c_str(), + this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")), this->Quiet); } - if (const char* changeId = - this->Makefile->GetDefinition("CTEST_CHANGE_ID")) { - this->CTest->SetCTestConfiguration("ChangeId", changeId, this->Quiet); + if (cmProp changeId = this->Makefile->GetDef("CTEST_CHANGE_ID")) { + this->CTest->SetCTestConfiguration("ChangeId", *changeId, this->Quiet); } cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl;); diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 85b8ab1..8b31e4b 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -326,6 +326,9 @@ void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml) case cmCTestMemCheckHandler::BOUNDS_CHECKER: xml.Attribute("Checker", "BoundsChecker"); break; + case cmCTestMemCheckHandler::CUDA_MEMCHECK: + xml.Attribute("Checker", "CudaMemcheck"); + break; case cmCTestMemCheckHandler::ADDRESS_SANITIZER: xml.Attribute("Checker", "AddressSanitizer"); break; @@ -351,7 +354,7 @@ void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml) cmCTestMemCheckHandler::TestResultsVector::size_type cc; for (cmCTestTestResult const& result : this->TestResults) { std::string testPath = result.Path + "/" + result.Name; - xml.Element("Test", this->CTest->GetShortPathToFile(testPath.c_str())); + xml.Element("Test", this->CTest->GetShortPathToFile(testPath)); } xml.EndElement(); // TestList cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, @@ -465,6 +468,8 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY; } else if (testerName.find("BC") != std::string::npos) { this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER; + } else if (testerName.find("cuda-memcheck") != std::string::npos) { + this->MemoryTesterStyle = cmCTestMemCheckHandler::CUDA_MEMCHECK; } else { this->MemoryTesterStyle = cmCTestMemCheckHandler::UNKNOWN; } @@ -485,6 +490,11 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() this->MemoryTester = this->CTest->GetCTestConfiguration("BoundsCheckerCommand"); this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER; + } else if (cmSystemTools::FileExists( + this->CTest->GetCTestConfiguration("CudaMemcheckCommand"))) { + this->MemoryTester = + this->CTest->GetCTestConfiguration("CudaMemcheckCommand"); + this->MemoryTesterStyle = cmCTestMemCheckHandler::CUDA_MEMCHECK; } if (this->CTest->GetCTestConfiguration("MemoryCheckType") == "AddressSanitizer") { @@ -528,6 +538,8 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND; } else if (checkType == "DrMemory") { this->MemoryTesterStyle = cmCTestMemCheckHandler::DRMEMORY; + } else if (checkType == "CudaMemcheck") { + this->MemoryTesterStyle = cmCTestMemCheckHandler::CUDA_MEMCHECK; } } if (this->MemoryTester.empty()) { @@ -553,6 +565,10 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() .empty()) { memoryTesterOptions = this->CTest->GetCTestConfiguration("DrMemoryCommandOptions"); + } else if (!this->CTest->GetCTestConfiguration("CudaMemcheckCommandOptions") + .empty()) { + memoryTesterOptions = + this->CTest->GetCTestConfiguration("CudaMemcheckCommandOptions"); } this->MemoryTesterOptions = cmSystemTools::ParseArguments(memoryTesterOptions); @@ -686,6 +702,18 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() this->MemoryTesterOptions.emplace_back("/M"); break; } + case cmCTestMemCheckHandler::CUDA_MEMCHECK: { + // cuda-memcheck separates flags from arguments by spaces + if (this->MemoryTesterOptions.empty()) { + this->MemoryTesterOptions.emplace_back("--tool"); + this->MemoryTesterOptions.emplace_back("memcheck"); + this->MemoryTesterOptions.emplace_back("--leak-check"); + this->MemoryTesterOptions.emplace_back("full"); + } + this->MemoryTesterDynamicOptions.emplace_back("--log-file"); + this->MemoryTesterDynamicOptions.push_back(this->MemoryTesterOutputFile); + break; + } // these are almost the same but the env var used is different case cmCTestMemCheckHandler::ADDRESS_SANITIZER: case cmCTestMemCheckHandler::LEAK_SANITIZER: @@ -771,6 +799,8 @@ bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str, return this->ProcessMemCheckSanitizerOutput(str, log, results); case cmCTestMemCheckHandler::BOUNDS_CHECKER: return this->ProcessMemCheckBoundsCheckerOutput(str, log, results); + case cmCTestMemCheckHandler::CUDA_MEMCHECK: + return this->ProcessMemCheckCudaOutput(str, log, results); default: log.append("\nMemory checking style used was: "); log.append("None that I know"); @@ -1103,6 +1133,119 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput( return defects == 0; } +bool cmCTestMemCheckHandler::ProcessMemCheckCudaOutput( + const std::string& str, std::string& log, std::vector<int>& results) +{ + std::vector<std::string> lines; + cmsys::SystemTools::Split(str, lines); + bool unlimitedOutput = false; + if (str.find("CTEST_FULL_OUTPUT") != std::string::npos || + this->CustomMaximumFailedTestOutputSize == 0) { + unlimitedOutput = true; + } + + std::string::size_type cc; + + std::ostringstream ostr; + log.clear(); + + int defects = 0; + + cmsys::RegularExpression memcheckLine("^========"); + + cmsys::RegularExpression leakExpr("== Leaked [0-9,]+ bytes at"); + + // list of matchers for output messages that contain variable content + // (addresses, sizes, ...) or can be shortened in general. the first match is + // used as a error name. + std::vector<cmsys::RegularExpression> matchers{ + // API errors + "== Malloc/Free error encountered: (.*)", + "== Program hit error ([^ ]*).* on CUDA API call to", + "== Program hit ([^ ]*).* on CUDA API call to", + // memcheck + "== (Invalid .*) of size [0-9,]+", "== (Fatal UVM [CG]PU fault)", + // racecheck + "== .* (Potential .* hazard detected)", "== .* (Race reported)", + // synccheck + "== (Barrier error)", + // initcheck + "== (Uninitialized .* memory read)", "== (Unused memory)", + "== (Host API memory access error)", + // generic error: ignore ERROR SUMMARY, CUDA-MEMCHECK and others + "== ([A-Z][a-z].*)" + }; + + std::vector<std::string::size_type> nonMemcheckOutput; + auto sttime = std::chrono::steady_clock::now(); + cmCTestOptionalLog(this->CTest, DEBUG, + "Start test: " << lines.size() << std::endl, this->Quiet); + std::string::size_type totalOutputSize = 0; + for (cc = 0; cc < lines.size(); cc++) { + cmCTestOptionalLog(this->CTest, DEBUG, + "test line " << lines[cc] << std::endl, this->Quiet); + + if (memcheckLine.find(lines[cc])) { + cmCTestOptionalLog(this->CTest, DEBUG, + "cuda-memcheck line " << lines[cc] << std::endl, + this->Quiet); + int failure = -1; + auto& line = lines[cc]; + if (leakExpr.find(line)) { + failure = static_cast<int>(this->FindOrAddWarning("Memory leak")); + } else { + for (auto& matcher : matchers) { + if (matcher.find(line)) { + failure = + static_cast<int>(this->FindOrAddWarning(matcher.match(1))); + break; + } + } + } + + if (failure >= 0) { + ostr << "<b>" << this->ResultStrings[failure] << "</b> "; + if (results.empty() || unsigned(failure) > results.size() - 1) { + results.push_back(1); + } else { + results[failure]++; + } + defects++; + } + totalOutputSize += lines[cc].size(); + ostr << lines[cc] << std::endl; + } else { + nonMemcheckOutput.push_back(cc); + } + } + // Now put all all the non cuda-memcheck output into the test output + // This should be last in case it gets truncated by the output + // limiting code + for (std::string::size_type i : nonMemcheckOutput) { + totalOutputSize += lines[i].size(); + ostr << lines[i] << std::endl; + if (!unlimitedOutput && + totalOutputSize > + static_cast<size_t>(this->CustomMaximumFailedTestOutputSize)) { + ostr << "....\n"; + ostr << "Test Output for this test has been truncated see testing" + " machine logs for full output,\n"; + ostr << "or put CTEST_FULL_OUTPUT in the output of " + "this test program.\n"; + break; // stop the copy of output if we are full + } + } + cmCTestOptionalLog(this->CTest, DEBUG, + "End test (elapsed: " + << cmDurationTo<unsigned int>( + std::chrono::steady_clock::now() - sttime) + << "s)" << std::endl, + this->Quiet); + log = ostr.str(); + this->DefectCount += defects; + return defects == 0; +} + // PostProcessTest memcheck results void cmCTestMemCheckHandler::PostProcessTest(cmCTestTestResult& res, int test) { diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h index 52667f8..63ab573 100644 --- a/Source/CTest/cmCTestMemCheckHandler.h +++ b/Source/CTest/cmCTestMemCheckHandler.h @@ -46,6 +46,7 @@ private: DRMEMORY, BOUNDS_CHECKER, // checkers after here do not use the standard error list + CUDA_MEMCHECK, ADDRESS_SANITIZER, LEAK_SANITIZER, THREAD_SANITIZER, @@ -137,6 +138,8 @@ private: std::vector<int>& results); bool ProcessMemCheckPurifyOutput(const std::string& str, std::string& log, std::vector<int>& results); + bool ProcessMemCheckCudaOutput(const std::string& str, std::string& log, + std::vector<int>& results); bool ProcessMemCheckSanitizerOutput(const std::string& str, std::string& log, std::vector<int>& results); bool ProcessMemCheckBoundsCheckerOutput(const std::string& str, diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.cxx b/Source/CTest/cmCTestReadCustomFilesCommand.cxx index ed14d06..a25cca4 100644 --- a/Source/CTest/cmCTestReadCustomFilesCommand.cxx +++ b/Source/CTest/cmCTestReadCustomFilesCommand.cxx @@ -15,7 +15,7 @@ bool cmCTestReadCustomFilesCommand::InitialPass( } for (std::string const& arg : args) { - this->CTest->ReadCustomConfigurationFileTree(arg.c_str(), this->Makefile); + this->CTest->ReadCustomConfigurationFileTree(arg, this->Makefile); } return true; diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 2c8e385..4d65c9b 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -619,11 +619,11 @@ void cmCTestRunTest::ComputeArguments() cmCTestMemCheckHandler* handler = static_cast<cmCTestMemCheckHandler*>(this->TestHandler); this->ActualCommand = handler->MemoryTester; - this->TestProperties->Args[1] = this->TestHandler->FindTheExecutable( - this->TestProperties->Args[1].c_str()); + this->TestProperties->Args[1] = + this->TestHandler->FindTheExecutable(this->TestProperties->Args[1]); } else { - this->ActualCommand = this->TestHandler->FindTheExecutable( - this->TestProperties->Args[1].c_str()); + this->ActualCommand = + this->TestHandler->FindTheExecutable(this->TestProperties->Args[1]); ++j; // skip the executable (it will be actualCommand) } std::string testCommand = diff --git a/Source/CTest/cmCTestStartCommand.cxx b/Source/CTest/cmCTestStartCommand.cxx index fe68406..6398d66 100644 --- a/Source/CTest/cmCTestStartCommand.cxx +++ b/Source/CTest/cmCTestStartCommand.cxx @@ -94,10 +94,9 @@ bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args, std::string sourceDir = cmSystemTools::CollapseFullPath(src_dir); std::string binaryDir = cmSystemTools::CollapseFullPath(bld_dir); - this->CTest->SetCTestConfiguration("SourceDirectory", sourceDir.c_str(), - this->Quiet); - this->CTest->SetCTestConfiguration("BuildDirectory", binaryDir.c_str(), + this->CTest->SetCTestConfiguration("SourceDirectory", sourceDir, this->Quiet); + this->CTest->SetCTestConfiguration("BuildDirectory", binaryDir, this->Quiet); if (smodel) { cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index 279216e..026e98f 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -35,12 +35,12 @@ std::unique_ptr<cmCommand> cmCTestSubmitCommand::Clone() cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() { - const char* submitURL = !this->SubmitURL.empty() - ? this->SubmitURL.c_str() - : this->Makefile->GetDefinition("CTEST_SUBMIT_URL"); + const std::string* submitURL = !this->SubmitURL.empty() + ? &this->SubmitURL + : this->Makefile->GetDef("CTEST_SUBMIT_URL"); if (submitURL) { - this->CTest->SetCTestConfiguration("SubmitURL", submitURL, this->Quiet); + this->CTest->SetCTestConfiguration("SubmitURL", *submitURL, this->Quiet); } else { this->CTest->SetCTestConfigurationFromCMakeVariable( this->Makefile, "DropMethod", "CTEST_DROP_METHOD", this->Quiet); @@ -108,7 +108,7 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() if (this->PartsMentioned) { auto parts = cmMakeRange(this->Parts).transform([this](std::string const& arg) { - return this->CTest->GetPartFromName(arg.c_str()); + return this->CTest->GetPartFromName(arg); }); handler->SelectParts(std::set<cmCTest::Part>(parts.begin(), parts.end())); } @@ -177,7 +177,7 @@ void cmCTestSubmitCommand::CheckArguments( !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()); + cmCTest::Part p = this->CTest->GetPartFromName(arg); if (p == cmCTest::PartCount) { std::ostringstream e; e << "Part name \"" << arg << "\" is invalid."; diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index ea36df5..5b54573 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -797,7 +797,7 @@ int cmCTestSubmitHandler::ProcessHandler() gfile = gfile.substr(glen); cmCTestOptionalLog(this->CTest, DEBUG, "Glob file: " << gfile << std::endl, this->Quiet); - this->CTest->AddSubmitFile(cmCTest::PartCoverage, gfile.c_str()); + this->CTest->AddSubmitFile(cmCTest::PartCoverage, gfile); } } else { cmCTestLog(this->CTest, ERROR_MESSAGE, "Problem globbing" << std::endl); diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx index c71b409..cbc3c0c 100644 --- a/Source/CTest/cmCTestTestCommand.cxx +++ b/Source/CTest/cmCTestTestCommand.cxx @@ -13,6 +13,7 @@ #include "cmCTestTestHandler.h" #include "cmDuration.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmStringAlgorithms.h" void cmCTestTestCommand::BindArguments() @@ -116,13 +117,13 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() unsigned long testLoad; const char* ctestTestLoad = this->Makefile->GetDefinition("CTEST_TEST_LOAD"); if (!this->TestLoad.empty()) { - if (!cmStrToULong(this->TestLoad.c_str(), &testLoad)) { + if (!cmStrToULong(this->TestLoad, &testLoad)) { testLoad = 0; cmCTestLog(this->CTest, WARNING, "Invalid value for 'TEST_LOAD' : " << this->TestLoad << std::endl); } - } else if (ctestTestLoad && *ctestTestLoad) { + } else if (cmNonempty(ctestTestLoad)) { if (!cmStrToULong(ctestTestLoad, &testLoad)) { testLoad = 0; cmCTestLog(this->CTest, WARNING, @@ -134,10 +135,10 @@ cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler() } handler->SetTestLoad(testLoad); - if (const char* labelsForSubprojects = - this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) { + if (cmProp labelsForSubprojects = + this->Makefile->GetDef("CTEST_LABELS_FOR_SUBPROJECTS")) { this->CTest->SetCTestConfiguration("LabelsForSubprojects", - labelsForSubprojects, this->Quiet); + *labelsForSubprojects, this->Quiet); } handler->SetQuiet(this->Quiet); diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index d0dbaae..70e84ee 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -1374,7 +1374,7 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml) xml.StartElement("TestList"); for (cmCTestTestResult const& result : this->TestResults) { std::string testPath = result.Path + "/" + result.Name; - xml.Element("Test", this->CTest->GetShortPathToFile(testPath.c_str())); + xml.Element("Test", this->CTest->GetShortPathToFile(testPath)); } xml.EndElement(); // TestList for (cmCTestTestResult& result : this->TestResults) { @@ -1483,8 +1483,8 @@ void cmCTestTestHandler::WriteTestResultHeader(cmXMLWriter& xml, } std::string testPath = result.Path + "/" + result.Name; xml.Element("Name", result.Name); - xml.Element("Path", this->CTest->GetShortPathToFile(result.Path.c_str())); - xml.Element("FullName", this->CTest->GetShortPathToFile(testPath.c_str())); + xml.Element("Path", this->CTest->GetShortPathToFile(result.Path)); + xml.Element("FullName", this->CTest->GetShortPathToFile(testPath)); xml.Element("FullCommandLine", result.FullCommandLine); } @@ -1546,12 +1546,12 @@ int cmCTestTestHandler::ExecuteCommands(std::vector<std::string>& vec) } // Find the appropriate executable to run for a test -std::string cmCTestTestHandler::FindTheExecutable(const char* exe) +std::string cmCTestTestHandler::FindTheExecutable(const std::string& exe) { std::string resConfig; std::vector<std::string> extraPaths; std::vector<std::string> failedPaths; - if (strcmp(exe, "NOT_AVAILABLE") == 0) { + if (exe == "NOT_AVAILABLE") { return exe; } return cmCTestTestHandler::FindExecutable(this->CTest, exe, resConfig, @@ -1607,7 +1607,7 @@ void cmCTestTestHandler::AddConfigurations( // Find the appropriate executable to run for a test std::string cmCTestTestHandler::FindExecutable( - cmCTest* ctest, const char* testCommand, std::string& resultingConfig, + cmCTest* ctest, const std::string& testCommand, std::string& resultingConfig, std::vector<std::string>& extraPaths, std::vector<std::string>& failed) { // now run the compiled test if we can find it diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index 0d88c30..b26f8a6 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -198,7 +198,8 @@ public: std::string filepath, std::string& filename); // full signature static method to find an executable - static std::string FindExecutable(cmCTest* ctest, const char* testCommand, + static std::string FindExecutable(cmCTest* ctest, + const std::string& testCommand, std::string& resultingConfig, std::vector<std::string>& extraPaths, std::vector<std::string>& failed); @@ -309,7 +310,7 @@ private: /** * Find the executable for a test */ - std::string FindTheExecutable(const char* exe); + std::string FindTheExecutable(const std::string& exe); std::string GetTestStatus(cmCTestTestResult const&); void ExpandTestsToRunInformation(size_t numPossibleTests); diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx index 673eb9a..95cae13 100644 --- a/Source/CTest/cmCTestUpdateCommand.cxx +++ b/Source/CTest/cmCTestUpdateCommand.cxx @@ -11,14 +11,13 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler() { if (!this->Source.empty()) { this->CTest->SetCTestConfiguration( - "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source).c_str(), + "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source), this->Quiet); } else { this->CTest->SetCTestConfiguration( "SourceDirectory", cmSystemTools::CollapseFullPath( - this->Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY")) - .c_str(), + this->Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY")), this->Quiet); } std::string source_dir = diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index a549117..9ee1c17 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -545,17 +545,17 @@ std::string cmProcess::GetExitExceptionString() # endif # ifdef SIGABRT case SIGABRT: - exception_str = "Child aborted"; + exception_str = "Subprocess aborted"; break; # endif # ifdef SIGKILL case SIGKILL: - exception_str = "Child killed"; + exception_str = "Subprocess killed"; break; # endif # ifdef SIGTERM case SIGTERM: - exception_str = "Child terminated"; + exception_str = "Subprocess terminated"; break; # endif # ifdef SIGHUP diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake index 50ccc7c..e726fc7 100644 --- a/Source/Checks/cm_cxx_features.cmake +++ b/Source/Checks/cm_cxx_features.cmake @@ -63,3 +63,8 @@ if(CMake_HAVE_CXX_MAKE_UNIQUE) set(CMake_HAVE_CXX_UNIQUE_PTR 1) endif() cm_check_cxx_feature(unique_ptr) +if (NOT CMAKE_CXX_STANDARD LESS "17") + cm_check_cxx_feature(filesystem) +else() + set(CMake_HAVE_CXX_FILESYSTEM FALSE) +endif() diff --git a/Source/Checks/cm_cxx_filesystem.cxx b/Source/Checks/cm_cxx_filesystem.cxx new file mode 100644 index 0000000..e508d1c --- /dev/null +++ b/Source/Checks/cm_cxx_filesystem.cxx @@ -0,0 +1,10 @@ + +#include <filesystem> + +int main() +{ + std::filesystem::path p1("/a/b/c"); + std::filesystem::path p2("/a/b/c"); + + return p1 == p2 ? 0 : 1; +} diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx index 9a26db5..85e256b 100644 --- a/Source/CursesDialog/ccmake.cxx +++ b/Source/CursesDialog/ccmake.cxx @@ -2,11 +2,15 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include <csignal> +#include <cstdio> +#include <cstdlib> #include <cstring> #include <iostream> #include <string> #include <vector> +#include <unistd.h> + #include "cmsys/Encoding.hxx" #include "cmCursesColor.h" @@ -54,7 +58,12 @@ void onsig(int /*unused*/) { if (cmCursesForm::CurrentForm) { endwin(); - initscr(); /* Initialization */ + if (initscr() == nullptr) { + static const char errmsg[] = "Error: ncurses initialization failed\n"; + auto r = write(STDERR_FILENO, errmsg, sizeof(errmsg) - 1); + static_cast<void>(r); + exit(1); + } noecho(); /* Echo off */ cbreak(); /* nl- or cr not needed */ keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ @@ -124,7 +133,10 @@ int main(int argc, char const* const* argv) cmCursesForm::DebugStart(); } - initscr(); /* Initialization */ + if (initscr() == nullptr) { + fprintf(stderr, "Error: ncurses initialization failed\n"); + exit(1); + } noecho(); /* Echo off */ cbreak(); /* nl- or cr not needed */ keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ diff --git a/Source/CursesDialog/form/CMakeLists.txt b/Source/CursesDialog/form/CMakeLists.txt index b468f5b..21c499e 100644 --- a/Source/CursesDialog/form/CMakeLists.txt +++ b/Source/CursesDialog/form/CMakeLists.txt @@ -3,6 +3,14 @@ project(CMAKE_FORM) +# Disable warnings to avoid changing 3rd party code. +if(CMAKE_C_COMPILER_ID MATCHES + "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel)$") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w") +elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall") +endif() + configure_file(cmFormConfigure.h.in "${CMAKE_CURRENT_BINARY_DIR}/cmFormConfigure.h") add_library(cmForm diff --git a/Source/CursesDialog/form/frm_driver.c b/Source/CursesDialog/form/frm_driver.c index e4e72aa..112ab08 100644 --- a/Source/CursesDialog/form/frm_driver.c +++ b/Source/CursesDialog/form/frm_driver.c @@ -2983,7 +2983,7 @@ INLINE static FIELD *Right_Neighbour_Field(FIELD * field) | Function : static FIELD *Upper_Neighbour_Field(FIELD * field) | | Description : Because of the row-major nature of sorting the fields, -| its more difficult to define whats the upper neighbour +| its more difficult to define what's the upper neighbour | field really means. We define that it must be on a | 'previous' line (cyclic order!) and is the rightmost | field laying on the left side of the given field. If @@ -3030,7 +3030,7 @@ static FIELD *Upper_Neighbour_Field(FIELD * field) | Function : static FIELD *Down_Neighbour_Field(FIELD * field) | | Description : Because of the row-major nature of sorting the fields, -| its more difficult to define whats the down neighbour +| its more difficult to define what's the down neighbour | field really means. We define that it must be on a | 'next' line (cyclic order!) and is the leftmost | field laying on the right side of the given field. If diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt index 98dd0e2..e6d6b17 100644 --- a/Source/QtDialog/CMakeLists.txt +++ b/Source/QtDialog/CMakeLists.txt @@ -3,111 +3,79 @@ project(QtDialog) CMake_OPTIONAL_COMPONENT(cmake-gui) -find_package(Qt5Widgets QUIET) -if (Qt5Widgets_FOUND) - include_directories(${Qt5Widgets_INCLUDE_DIRS}) - add_definitions(${Qt5Widgets_DEFINITONS}) - macro(qt4_wrap_ui) - qt5_wrap_ui(${ARGN}) - endmacro() - macro(qt4_wrap_cpp) - qt5_wrap_cpp(${ARGN}) - endmacro() - macro(qt4_add_resources) - qt5_add_resources(${ARGN}) - endmacro() +find_package(Qt5Widgets REQUIRED) - set(CMake_QT_LIBRARIES ${Qt5Widgets_LIBRARIES}) - set(QT_QTMAIN_LIBRARY ${Qt5Core_QTMAIN_LIBRARIES}) +set(CMake_QT_EXTRA_LIBRARIES) - # Try to find the package WinExtras for the task bar progress - if(WIN32) - find_package(Qt5WinExtras QUIET) - if (Qt5WinExtras_FOUND) - include_directories(${Qt5WinExtras_INCLUDE_DIRS}) - add_definitions(-DQT_WINEXTRAS) - list(APPEND CMake_QT_LIBRARIES ${Qt5WinExtras_LIBRARIES}) - endif() +# Try to find the package WinExtras for the task bar progress +if(WIN32) + find_package(Qt5WinExtras QUIET) + if (Qt5WinExtras_FOUND) + add_definitions(-DQT_WINEXTRAS) + list(APPEND CMake_QT_EXTRA_LIBRARIES Qt5::WinExtras) endif() +endif() - # Remove this when the minimum version of Qt is 4.6. - add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0) - - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") - if(CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES) - list(APPEND CMake_QT_LIBRARIES ${CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES}) - set_property(SOURCE CMakeSetup.cxx - PROPERTY COMPILE_DEFINITIONS USE_QXcbIntegrationPlugin) - endif() +if(CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES) + list(APPEND CMake_QT_EXTRA_LIBRARIES ${CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES}) + set_property(SOURCE CMakeSetup.cxx + PROPERTY COMPILE_DEFINITIONS USE_QXcbIntegrationPlugin) +endif() - if(CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES) - list(APPEND CMake_QT_LIBRARIES ${CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES}) - set_property(SOURCE CMakeSetup.cxx - PROPERTY COMPILE_DEFINITIONS USE_QWindowsIntegrationPlugin) - endif() +if(CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES) + list(APPEND CMake_QT_EXTRA_LIBRARIES ${CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES}) + set_property(SOURCE CMakeSetup.cxx + PROPERTY COMPILE_DEFINITIONS USE_QWindowsIntegrationPlugin) +endif() - # We need to install platform plugin and add qt.conf for Qt5 on Mac and Windows. - # FIXME: This should be part of Qt5 CMake scripts, but unfortunately - # Qt5 support is missing there. - if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32)) - macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var) - get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION) - if(EXISTS "${_qt_plugin_path}") - get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME) - get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH) - get_filename_component(_qt_plugin_type "${_qt_plugin_type}" NAME) - if(APPLE) - set(_qt_plugin_dir "PlugIns") - elseif(WIN32) - set(_qt_plugin_dir "plugins") - endif() - set(_qt_plugin_dest "${_qt_plugin_dir}/${_qt_plugin_type}") - install(FILES "${_qt_plugin_path}" - DESTINATION "${_qt_plugin_dest}" - ${COMPONENT}) - set(${_qt_plugins_var} - "${${_qt_plugins_var}};\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${_qt_plugin_dest}/${_qt_plugin_file}") - else() - message(FATAL_ERROR "QT plugin ${_qt_plugin_name} not found") +# We need to install platform plugin and add qt.conf for Qt5 on Mac and Windows. +# FIXME: This should be part of Qt5 CMake scripts, but unfortunately +# Qt5 support is missing there. +if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32)) + macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var) + get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION) + if(EXISTS "${_qt_plugin_path}") + get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME) + get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH) + get_filename_component(_qt_plugin_type "${_qt_plugin_type}" NAME) + if(APPLE) + set(_qt_plugin_dir "PlugIns") + elseif(WIN32) + set(_qt_plugin_dir "plugins") endif() - endmacro() - if(APPLE) - install_qt5_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS) - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" - "[Paths]\nPlugins = ${_qt_plugin_dir}\n") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" - DESTINATION "${CMAKE_INSTALL_PREFIX}/Resources" + set(_qt_plugin_dest "${_qt_plugin_dir}/${_qt_plugin_type}") + install(FILES "${_qt_plugin_path}" + DESTINATION "${_qt_plugin_dest}" ${COMPONENT}) - elseif(WIN32 AND NOT CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES) - install_qt5_plugin("Qt5::QWindowsIntegrationPlugin" QT_PLUGINS) - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" - "[Paths]\nPlugins = ../${_qt_plugin_dir}\n") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" - DESTINATION bin - ${COMPONENT}) - endif() - endif() - - if(TARGET Qt5::Core) - get_property(_Qt5_Core_LOCATION TARGET Qt5::Core PROPERTY LOCATION) - get_filename_component(Qt_BIN_DIR "${_Qt5_Core_LOCATION}" PATH) - if(APPLE) - get_filename_component(Qt_BIN_DIR "${Qt_BIN_DIR}" PATH) + set(${_qt_plugins_var} + "${${_qt_plugins_var}};\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${_qt_plugin_dest}/${_qt_plugin_file}") + else() + message(FATAL_ERROR "QT plugin ${_qt_plugin_name} not found") endif() + endmacro() + if(APPLE) + install_qt5_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" + "[Paths]\nPlugins = ${_qt_plugin_dir}\n") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" + DESTINATION "${CMAKE_INSTALL_PREFIX}/Resources" + ${COMPONENT}) + elseif(WIN32 AND NOT CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES) + install_qt5_plugin("Qt5::QWindowsIntegrationPlugin" QT_PLUGINS) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" + "[Paths]\nPlugins = ../${_qt_plugin_dir}\n") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" + DESTINATION bin + ${COMPONENT}) endif() -else() - set(QT_MIN_VERSION "4.4.0") - find_package(Qt4 REQUIRED) - if(NOT QT4_FOUND) - message(SEND_ERROR "Failed to find Qt 4.4 or greater.") - return() - endif() - - include(${QT_USE_FILE}) - - set(CMake_QT_LIBRARIES ${QT_LIBRARIES}) +endif() +get_property(_Qt5_Core_LOCATION TARGET Qt5::Core PROPERTY LOCATION) +get_filename_component(Qt_BIN_DIR "${_Qt5_Core_LOCATION}" PATH) +if(APPLE) + get_filename_component(Qt_BIN_DIR "${Qt_BIN_DIR}" PATH) endif() set(SRCS @@ -116,6 +84,7 @@ set(SRCS CMakeSetup.cxx CMakeSetupDialog.cxx CMakeSetupDialog.h + Compilers.h FirstConfigure.cxx FirstConfigure.h QCMake.cxx @@ -129,7 +98,7 @@ set(SRCS WarningMessagesDialog.cxx WarningMessagesDialog.h ) -QT4_WRAP_UI(UI_SRCS +qt5_wrap_ui(UI_SRCS CMakeSetupDialog.ui Compilers.ui CrossCompiler.ui @@ -137,7 +106,7 @@ QT4_WRAP_UI(UI_SRCS RegexExplorer.ui WarningMessagesDialog.ui ) -QT4_WRAP_CPP(MOC_SRCS +qt5_wrap_cpp(MOC_SRCS AddCacheEntry.h Compilers.h CMakeSetupDialog.h @@ -148,14 +117,24 @@ QT4_WRAP_CPP(MOC_SRCS RegexExplorer.h WarningMessagesDialog.h ) -QT4_ADD_RESOURCES(RC_SRCS CMakeSetup.qrc) +qt5_add_resources(RC_SRCS CMakeSetup.qrc) + +if (FALSE) # CMake's bootstrap binary does not support automoc + set(CMAKE_AUTOMOC 1) + set(CMAKE_AUTORCC 1) + set(CMAKE_AUTOUIC 1) +else () + list(APPEND SRCS + ${UI_SRCS} + ${MOC_SRCS} + ${RC_SRCS}) +endif () -set(SRCS ${SRCS} ${UI_SRCS} ${MOC_SRCS} ${RC_SRCS}) if(WIN32) - set(SRCS ${SRCS} CMakeSetup.rc) + list(APPEND SRCS CMakeSetup.rc) endif() if(APPLE) - set(SRCS ${SRCS} CMakeSetup.icns) + list(APPEND SRCS CMakeSetup.icns) set(MACOSX_BUNDLE_ICON_FILE CMakeSetup.icns) set_source_files_properties(CMakeSetup.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources) @@ -172,7 +151,7 @@ endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) add_executable(cmake-gui WIN32 MACOSX_BUNDLE ${SRCS} ${MANIFEST_FILE}) -target_link_libraries(cmake-gui CMakeLib ${QT_QTMAIN_LIBRARY} ${CMake_QT_LIBRARIES}) +target_link_libraries(cmake-gui CMakeLib Qt5::Core Qt5::Widgets ${CMake_QT_EXTRA_LIBRARIES}) if(WIN32) target_sources(cmake-gui PRIVATE $<TARGET_OBJECTS:CMakeVersion>) diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index 9d928b2..7ef5a72 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -115,14 +115,6 @@ int main(int argc, char** argv) QTextCodec* utf8_codec = QTextCodec::codecForName("UTF-8"); QTextCodec::setCodecForLocale(utf8_codec); -#if QT_VERSION < 0x050000 - // clean out standard Qt paths for plugins, which we don't use anyway - // when creating Mac bundles, it potentially causes problems - foreach (QString p, QApplication::libraryPaths()) { - QApplication::removeLibraryPath(p); - } -#endif - // tell the cmake library where cmake is QDir cmExecDir(QApplication::applicationDirPath()); #if defined(Q_OS_MAC) diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index 6dbfe11..fcc8408 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -152,9 +152,6 @@ CMakeSetupDialog::CMakeSetupDialog() this->WarnUninitializedAction = OptionsMenu->addAction(tr("&Warn Uninitialized (--warn-uninitialized)")); this->WarnUninitializedAction->setCheckable(true); - this->WarnUnusedAction = - OptionsMenu->addAction(tr("&Warn Unused (--warn-unused-vars)")); - this->WarnUnusedAction->setCheckable(true); QAction* debugAction = OptionsMenu->addAction(tr("&Debug Output")); debugAction->setCheckable(true); @@ -290,9 +287,6 @@ void CMakeSetupDialog::initialize() QObject::connect(this->WarnUninitializedAction, SIGNAL(triggered(bool)), this->CMakeThread->cmakeInstance(), SLOT(setWarnUninitializedMode(bool))); - QObject::connect(this->WarnUnusedAction, SIGNAL(triggered(bool)), - this->CMakeThread->cmakeInstance(), - SLOT(setWarnUnusedMode(bool))); if (!this->SourceDirectory->text().isEmpty() || !this->BinaryDirectory->lineEdit()->text().isEmpty()) { diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h index d1e2035..914be12 100644 --- a/Source/QtDialog/CMakeSetupDialog.h +++ b/Source/QtDialog/CMakeSetupDialog.h @@ -111,7 +111,6 @@ protected: QAction* ConfigureAction; QAction* GenerateAction; QAction* WarnUninitializedAction; - QAction* WarnUnusedAction; QAction* InstallForCommandLineAction; State CurrentState; diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx index 776af81..6090256 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -21,7 +21,6 @@ QCMake::QCMake(QObject* p) : QObject(p) { this->WarnUninitializedMode = false; - this->WarnUnusedMode = false; qRegisterMetaType<QCMakeProperty>(); qRegisterMetaType<QCMakePropertyList>(); @@ -170,7 +169,6 @@ void QCMake::configure() this->CMakeInstance->SetGeneratorToolset(this->Toolset.toLocal8Bit().data()); this->CMakeInstance->LoadCache(); this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode); - this->CMakeInstance->SetWarnUnused(this->WarnUnusedMode); this->CMakeInstance->PreLoadCMakeFiles(); InterruptFlag = 0; @@ -340,10 +338,10 @@ void QCMake::interrupt() bool QCMake::interruptCallback() { -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - return this->InterruptFlag; -#else +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) return this->InterruptFlag.load(); +#else + return this->InterruptFlag.loadRelaxed(); #endif } @@ -478,11 +476,6 @@ void QCMake::setWarnUninitializedMode(bool value) this->WarnUninitializedMode = value; } -void QCMake::setWarnUnusedMode(bool value) -{ - this->WarnUnusedMode = value; -} - void QCMake::checkOpenPossible() { std::string data = this->BinaryDirectory.toLocal8Bit().data(); diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h index 110a971..39555d6 100644 --- a/Source/QtDialog/QCMake.h +++ b/Source/QtDialog/QCMake.h @@ -114,8 +114,6 @@ public slots: void setDeprecatedWarningsAsErrors(bool value); /// set whether to run cmake with warnings about uninitialized variables void setWarnUninitializedMode(bool value); - /// set whether to run cmake with warnings about unused variables - void setWarnUnusedMode(bool value); /// check if project IDE open is possible and emit openPossible signal void checkOpenPossible(); @@ -175,8 +173,6 @@ protected: void stderrCallback(std::string const& msg); bool WarnUninitializedMode; - bool WarnUnusedMode; - bool WarnUnusedAllMode; QString SourceDirectory; QString BinaryDirectory; QString Generator; diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx index 9b24fbd..3bf4409 100644 --- a/Source/QtDialog/QCMakeCacheView.cxx +++ b/Source/QtDialog/QCMakeCacheView.cxx @@ -155,11 +155,7 @@ QModelIndex QCMakeCacheView::moveCursor(CursorAction act, void QCMakeCacheView::setShowAdvanced(bool s) { -#if QT_VERSION >= 040300 - // new 4.3 API that needs to be called. what about an older Qt? this->SearchFilter->invalidate(); -#endif - this->AdvancedFilter->setShowAdvanced(s); } @@ -209,9 +205,7 @@ 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; @@ -335,11 +329,7 @@ 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 @@ -349,9 +339,7 @@ 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; @@ -368,11 +356,7 @@ 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, @@ -498,8 +482,7 @@ QCMakePropertyList QCMakeCacheModel::properties() const // go to the next in the tree while (!idxs.isEmpty() && ( -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) && \ - QT_VERSION < QT_VERSION_CHECK(5, 1, 0) +#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0) (idxs.last().row() + 1) >= rowCount(idxs.last().parent()) || #endif !idxs.last().sibling(idxs.last().row() + 1, 0).isValid())) { @@ -659,20 +642,6 @@ bool QCMakeCacheModelDelegate::editorEvent(QEvent* e, return success; } -// Issue 205903 fixed in Qt 4.5.0. -// Can remove this function and FileDialogFlag when minimum Qt version is 4.5 -bool QCMakeCacheModelDelegate::eventFilter(QObject* object, QEvent* evt) -{ - // workaround for what looks like a bug in Qt on macOS - // where it doesn't create a QWidget wrapper for the native file dialog - // so the Qt library ends up assuming the focus was lost to something else - - if (evt->type() == QEvent::FocusOut && this->FileDialogFlag) { - return false; - } - return QItemDelegate::eventFilter(object, evt); -} - void QCMakeCacheModelDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const diff --git a/Source/QtDialog/QCMakeCacheView.h b/Source/QtDialog/QCMakeCacheView.h index bea1965..a252708 100644 --- a/Source/QtDialog/QCMakeCacheView.h +++ b/Source/QtDialog/QCMakeCacheView.h @@ -144,7 +144,6 @@ public: bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index); - bool eventFilter(QObject* object, QEvent* event); void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; QSize sizeHint(const QStyleOptionViewItem& option, diff --git a/Source/QtDialog/QCMakeWidgets.cxx b/Source/QtDialog/QCMakeWidgets.cxx index 332a770..d16ea58 100644 --- a/Source/QtDialog/QCMakeWidgets.cxx +++ b/Source/QtDialog/QCMakeWidgets.cxx @@ -4,9 +4,9 @@ #include <utility> -#include <QDirModel> #include <QFileDialog> #include <QFileInfo> +#include <QFileSystemModel> #include <QResizeEvent> #include <QToolButton> @@ -88,20 +88,20 @@ void QCMakePathEditor::chooseFile() } } -// use same QDirModel for all completers -static QDirModel* fileDirModel() +// use same QFileSystemModel for all completers +static QFileSystemModel* fileDirModel() { - static QDirModel* m = nullptr; + static QFileSystemModel* m = nullptr; if (!m) { - m = new QDirModel(); + m = new QFileSystemModel(); } return m; } -static QDirModel* pathDirModel() +static QFileSystemModel* pathDirModel() { - static QDirModel* m = nullptr; + static QFileSystemModel* m = nullptr; if (!m) { - m = new QDirModel(); + m = new QFileSystemModel(); m->setFilter(QDir::AllDirs | QDir::Drives | QDir::NoDotAndDotDot); } return m; @@ -110,7 +110,7 @@ static QDirModel* pathDirModel() QCMakeFileCompleter::QCMakeFileCompleter(QObject* o, bool dirs) : QCompleter(o) { - QDirModel* m = dirs ? pathDirModel() : fileDirModel(); + QFileSystemModel* m = dirs ? pathDirModel() : fileDirModel(); this->setModel(m); } diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index 3e5d764..f262fac 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -2,8 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmAddLibraryCommand.h" -#include <cmext/algorithm> - #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" @@ -111,20 +109,10 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args, "INTERFACE library specified with conflicting ALIAS type."); return false; } - if (excludeFromAll) { - status.SetError( - "INTERFACE library may not be used with EXCLUDE_FROM_ALL."); - return false; - } ++s; type = cmStateEnums::INTERFACE_LIBRARY; haveSpecifiedType = true; } else if (*s == "EXCLUDE_FROM_ALL") { - if (type == cmStateEnums::INTERFACE_LIBRARY) { - status.SetError( - "INTERFACE library may not be used with EXCLUDE_FROM_ALL."); - return false; - } ++s; excludeFromAll = true; } else if (*s == "IMPORTED") { @@ -143,10 +131,6 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args, } if (type == cmStateEnums::INTERFACE_LIBRARY) { - if (s != args.end()) { - status.SetError("INTERFACE library requires no source arguments."); - return false; - } if (importGlobal && !importTarget) { status.SetError( "INTERFACE library specified as GLOBAL, but not as IMPORTED."); @@ -302,8 +286,6 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args, } } - std::vector<std::string> srclists; - if (type == cmStateEnums::INTERFACE_LIBRARY) { if (!cmGeneratorExpression::IsValidTargetName(libName) || libName.find("::") != std::string::npos) { @@ -311,14 +293,10 @@ bool cmAddLibraryCommand(std::vector<std::string> const& args, cmStrCat("Invalid name for INTERFACE library target: ", libName)); return false; } - - mf.AddLibrary(libName, type, srclists, excludeFromAll); - return true; } - cm::append(srclists, s, args.end()); - - mf.AddLibrary(libName, type, srclists, excludeFromAll); + std::vector<std::string> srcs(s, args.end()); + mf.AddLibrary(libName, type, srcs, excludeFromAll); return true; } diff --git a/Source/cmAuxSourceDirectoryCommand.cxx b/Source/cmAuxSourceDirectoryCommand.cxx index d6f7500e..53d4cb4 100644 --- a/Source/cmAuxSourceDirectoryCommand.cxx +++ b/Source/cmAuxSourceDirectoryCommand.cxx @@ -55,7 +55,7 @@ bool cmAuxSourceDirectoryCommand(std::vector<std::string> const& args, auto ext = cm::string_view(file).substr(dotpos + 1); // Process only source files auto cm = mf.GetCMakeInstance(); - if (dotpos > 0 && cm->IsSourceExtension(ext)) { + if (dotpos > 0 && cm->IsACLikeSourceExtension(ext)) { std::string fullname = cmStrCat(templateDirectory, '/', file); // add the file as a class file so // depends can be done diff --git a/Source/cmCMakeLanguageCommand.h b/Source/cmCMakeLanguageCommand.h index 7306515..aeb8f60 100644 --- a/Source/cmCMakeLanguageCommand.h +++ b/Source/cmCMakeLanguageCommand.h @@ -11,7 +11,7 @@ class cmExecutionStatus; struct cmListFileArgument; /** - * \brief Calls a scripted or build-in command + * \brief Calls a scripted or built-in command * */ bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args, diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index bca7540..a5fde89 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -394,7 +394,7 @@ bool cmCTest::ShouldCompressTestOutput() return this->Impl->CompressTestOutput; } -cmCTest::Part cmCTest::GetPartFromName(const char* name) +cmCTest::Part cmCTest::GetPartFromName(const std::string& name) { // Look up by lower-case to make names case-insensitive. std::string lower_name = cmSystemTools::LowerCase(name); @@ -458,8 +458,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command) cm.GetCurrentSnapshot().SetDefaultDefinitions(); cmGlobalGenerator gg(&cm); cmMakefile mf(&gg, cm.GetCurrentSnapshot()); - if (!this->ReadCustomConfigurationFileTree(this->Impl->BinaryDir.c_str(), - &mf)) { + if (!this->ReadCustomConfigurationFileTree(this->Impl->BinaryDir, &mf)) { cmCTestOptionalLog( this, DEBUG, "Cannot find custom configuration file tree" << std::endl, quiet); @@ -523,7 +522,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command) std::string model; if (cmSystemTools::GetLineFromStream(tfin, model) && !this->Impl->Parts[PartStart] && !command) { - this->Impl->TestModel = GetTestModelFromString(model.c_str()); + this->Impl->TestModel = GetTestModelFromString(model); } tfin.close(); } @@ -579,7 +578,7 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command) cmSystemTools::GetLineFromStream(tfin, tag); cmSystemTools::GetLineFromStream(tfin, group); if (cmSystemTools::GetLineFromStream(tfin, modelStr)) { - model = GetTestModelFromString(modelStr.c_str()); + model = GetTestModelFromString(modelStr); } tfin.close(); } @@ -793,7 +792,7 @@ int cmCTest::GetTestModel() const return this->Impl->TestModel; } -bool cmCTest::SetTest(const char* ttype, bool report) +bool cmCTest::SetTest(const std::string& ttype, bool report) { if (cmSystemTools::LowerCase(ttype) == "all") { for (Part p = PartStart; p != PartCount; p = Part(p + 1)) { @@ -841,6 +840,7 @@ bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name, } } std::string filename = testingDir + "/" + name; + stream.SetTempExt("tmp"); stream.Open(filename); if (!stream) { cmCTestLog(this, ERROR_MESSAGE, @@ -855,7 +855,7 @@ bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name, return true; } -bool cmCTest::AddIfExists(Part part, const char* file) +bool cmCTest::AddIfExists(Part part, const std::string& file) { if (this->CTestFileExists(file)) { this->AddSubmitFile(part, file); @@ -1007,7 +1007,7 @@ int cmCTest::ProcessSteps() if (this->Impl->Parts[PartNotes]) { this->UpdateCTestConfiguration(); if (!this->Impl->NotesFiles.empty()) { - this->GenerateNotesFile(this->Impl->NotesFiles.c_str()); + this->GenerateNotesFile(this->Impl->NotesFiles); } } if (this->Impl->Parts[PartSubmit]) { @@ -1036,9 +1036,9 @@ std::string cmCTest::GetTestModelString() return "Experimental"; } -int cmCTest::GetTestModelFromString(const char* str) +int cmCTest::GetTestModelFromString(const std::string& str) { - if (!str) { + if (str.empty()) { return cmCTest::EXPERIMENTAL; } std::string rstr = cmSystemTools::LowerCase(str); @@ -1564,9 +1564,9 @@ int cmCTest::GenerateNotesFile(std::vector<std::string> const& files) return 0; } -int cmCTest::GenerateNotesFile(const char* cfiles) +int cmCTest::GenerateNotesFile(const std::string& cfiles) { - if (!cfiles) { + if (cfiles.empty()) { return 1; } @@ -1649,14 +1649,14 @@ bool cmCTest::SubmitExtraFiles(std::vector<std::string> const& files) << std::endl;); return false; } - this->AddSubmitFile(PartExtraFiles, file.c_str()); + this->AddSubmitFile(PartExtraFiles, file); } return true; } -bool cmCTest::SubmitExtraFiles(const char* cfiles) +bool cmCTest::SubmitExtraFiles(const std::string& cfiles) { - if (!cfiles) { + if (cfiles.empty()) { return true; } @@ -1940,7 +1940,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, else if (this->CheckArgument(arg, "-C"_s, "--build-config") && i < args.size() - 1) { i++; - this->SetConfigType(args[i].c_str()); + this->SetConfigType(args[i]); } else if (this->CheckArgument(arg, "--debug"_s)) { @@ -2015,7 +2015,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, else if (this->CheckArgument(arg, "-O"_s, "--output-log") && i < args.size() - 1) { i++; - this->SetOutputLogFileName(args[i].c_str()); + this->SetOutputLogFileName(args[i]); } else if (this->CheckArgument(arg, "--tomorrow-tag"_s)) { @@ -2047,7 +2047,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, this->Impl->ProduceXML = true; this->SetTest("Notes"); i++; - this->SetNotesFiles(args[i].c_str()); + this->SetNotesFiles(args[i]); return true; } @@ -2304,7 +2304,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output) this->Impl->ProduceXML = true; this->SetTest("Submit"); i++; - if (!this->SubmitExtraFiles(args[i].c_str())) { + if (!this->SubmitExtraFiles(args[i])) { return 0; } } @@ -2375,7 +2375,7 @@ bool cmCTest::HandleTestActionArgument(const char* ctestExec, size_t& i, (i < args.size() - 1)) { this->Impl->ProduceXML = true; i++; - if (!this->SetTest(args[i].c_str(), false)) { + if (!this->SetTest(args[i], false)) { success = false; cmCTestLog(this, ERROR_MESSAGE, "CTest -T called with incorrect option: " << args[i] @@ -2490,11 +2490,8 @@ int cmCTest::RunCMakeAndTest(std::string* output) return retv; } -void cmCTest::SetNotesFiles(const char* notes) +void cmCTest::SetNotesFiles(const std::string& notes) { - if (!notes) { - return; - } this->Impl->NotesFiles = notes; } @@ -2560,7 +2557,8 @@ void cmCTest::SetScheduleType(std::string const& type) this->Impl->ScheduleType = type; } -int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf) +int cmCTest::ReadCustomConfigurationFileTree(const std::string& dir, + cmMakefile* mf) { bool found = false; cmCTestLog(this, DEBUG, @@ -2647,7 +2645,7 @@ void cmCTest::PopulateCustomInteger(cmMakefile* mf, const std::string& def, val = atoi(dval); } -std::string cmCTest::GetShortPathToFile(const char* cfname) +std::string cmCTest::GetShortPathToFile(const std::string& cfname) { const std::string& sourceDir = cmSystemTools::CollapseFullPath( this->GetCTestConfiguration("SourceDirectory")); @@ -2711,18 +2709,17 @@ void cmCTest::EmptyCTestConfiguration() this->Impl->CTestConfiguration.clear(); } -void cmCTest::SetCTestConfiguration(const char* name, const char* value, +void cmCTest::SetCTestConfiguration(const char* name, const std::string& value, bool suppress) { cmCTestOptionalLog(this, HANDLER_VERBOSE_OUTPUT, - "SetCTestConfiguration:" - << name << ":" << (value ? value : "(null)") << "\n", + "SetCTestConfiguration:" << name << ":" << value << "\n", suppress); if (!name) { return; } - if (!value) { + if (value.empty()) { this->Impl->CTestConfiguration.erase(name); return; } @@ -2927,7 +2924,7 @@ std::string cmCTest::GetBuildID() const return this->Impl->BuildID; } -void cmCTest::AddSubmitFile(Part part, const char* name) +void cmCTest::AddSubmitFile(Part part, const std::string& name) { this->Impl->Parts[part].SubmitFiles.emplace_back(name); } @@ -2963,9 +2960,9 @@ void cmCTest::AddCTestConfigurationOverwrite(const std::string& overStr) this->Impl->CTestConfigurationOverwrites[key] = value; } -void cmCTest::SetConfigType(const char* ct) +void cmCTest::SetConfigType(const std::string& ct) { - this->Impl->ConfigType = ct ? ct : ""; + this->Impl->ConfigType = ct; cmSystemTools::ReplaceString(this->Impl->ConfigType, ".\\", ""); std::string confTypeEnv = "CMAKE_CONFIG_TYPE=" + this->Impl->ConfigType; cmSystemTools::PutEnv(confTypeEnv); @@ -2975,8 +2972,7 @@ bool cmCTest::SetCTestConfigurationFromCMakeVariable( cmMakefile* mf, const char* dconfig, const std::string& cmake_var, bool suppress) { - const char* ctvar; - ctvar = mf->GetDefinition(cmake_var); + cmProp ctvar = mf->GetDef(cmake_var); if (!ctvar) { return false; } @@ -2984,7 +2980,7 @@ bool cmCTest::SetCTestConfigurationFromCMakeVariable( "SetCTestConfigurationFromCMakeVariable:" << dconfig << ":" << cmake_var << std::endl, suppress); - this->SetCTestConfiguration(dconfig, ctvar, suppress); + this->SetCTestConfiguration(dconfig, *ctvar, suppress); return true; } @@ -3085,9 +3081,9 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args, return result; } -void cmCTest::SetOutputLogFileName(const char* name) +void cmCTest::SetOutputLogFileName(const std::string& name) { - if (name) { + if (!name.empty()) { this->Impl->OutputLogFile = cm::make_unique<cmGeneratedFileStream>(name); } else { this->Impl->OutputLogFile.reset(); diff --git a/Source/cmCTest.h b/Source/cmCTest.h index a39b8fe..1e0fb8c 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -64,7 +64,7 @@ public: /** Get a testing part id from its string name. Returns PartCount if the string does not name a valid part. */ - Part GetPartFromName(const char* name); + Part GetPartFromName(const std::string& name); /** Process Command line arguments */ int Run(std::vector<std::string>&, std::string* output = nullptr); @@ -127,12 +127,12 @@ public: * Check if CTest file exists */ bool CTestFileExists(const std::string& filename); - bool AddIfExists(Part part, const char* file); + bool AddIfExists(Part part, const std::string& file); /** * Set the cmake test */ - bool SetTest(const char*, bool report = true); + bool SetTest(const std::string&, bool report = true); /** * Set the cmake test mode (experimental, nightly, continuous). @@ -141,11 +141,11 @@ public: int GetTestModel() const; std::string GetTestModelString(); - static int GetTestModelFromString(const char* str); + static int GetTestModelFromString(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, + void SetCTestConfiguration(const char* name, const std::string& value, bool suppress = false); void EmptyCTestConfiguration(); @@ -161,7 +161,7 @@ public: cmCTest& operator=(const cmCTest&) = delete; /** Set the notes files to be created. */ - void SetNotesFiles(const char* notes); + void SetNotesFiles(const std::string& notes); void PopulateCustomVector(cmMakefile* mf, const std::string& definition, std::vector<std::string>& vec); @@ -272,7 +272,7 @@ public: * This means if the file is in binary or * source directory, it will become /.../relative/path/to/file */ - std::string GetShortPathToFile(const char* fname); + std::string GetShortPathToFile(const std::string& fname); enum { @@ -354,14 +354,14 @@ public: int GenerateDoneFile(); /** Submit extra files to the server */ - bool SubmitExtraFiles(const char* files); + bool SubmitExtraFiles(const std::string& files); bool SubmitExtraFiles(std::vector<std::string> const& files); /** Set the output log file name */ - void SetOutputLogFileName(const char* name); + void SetOutputLogFileName(const std::string& name); /** Set the visual studio or Xcode config type */ - void SetConfigType(const char* ct); + void SetConfigType(const std::string& ct); /** Various log types */ enum @@ -399,14 +399,14 @@ public: std::string GetBuildID() const; /** Add file to be submitted */ - void AddSubmitFile(Part part, const char* name); + void AddSubmitFile(Part part, const std::string& name); std::vector<std::string> const& GetSubmitFiles(Part part) const; void ClearSubmitFiles(Part part); /** * Read the custom configuration files and apply them to the current ctest */ - int ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf); + int ReadCustomConfigurationFileTree(const std::string& dir, cmMakefile* mf); std::vector<std::string>& GetInitialCommandLineArguments(); @@ -462,7 +462,7 @@ public: void SetRunCurrentScript(bool value); private: - int GenerateNotesFile(const char* files); + int GenerateNotesFile(const std::string& files); void BlockTestErrorDiagnostics(); diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index 35bd681..95686ea 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -578,10 +578,7 @@ cmProp cmCacheManager::CacheEntry::GetProperty(const std::string& prop) const bool cmCacheManager::CacheEntry::GetPropertyAsBool( const std::string& prop) const { - if (cmProp value = this->GetProperty(prop)) { - return cmIsOn(*value); - } - return false; + return cmIsOn(this->GetProperty(prop)); } void cmCacheManager::CacheEntry::SetProperty(const std::string& prop, diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 051eff6..8aee27c 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -41,7 +41,7 @@ std::vector<std::string> const& cmCommonTargetGenerator::GetConfigNames() const const char* cmCommonTargetGenerator::GetFeature(const std::string& feature, const std::string& config) { - return this->GeneratorTarget->GetFeature(feature, config); + return this->GeneratorTarget->GetFeature(feature, config)->c_str(); } void cmCommonTargetGenerator::AddModuleDefinitionFlag( diff --git a/Source/cmComputeComponentGraph.cxx b/Source/cmComputeComponentGraph.cxx index 81cd878..6591fb1 100644 --- a/Source/cmComputeComponentGraph.cxx +++ b/Source/cmComputeComponentGraph.cxx @@ -8,6 +8,12 @@ cmComputeComponentGraph::cmComputeComponentGraph(Graph const& input) : InputGraph(input) { +} + +cmComputeComponentGraph::~cmComputeComponentGraph() = default; + +void cmComputeComponentGraph::Compute() +{ // Identify components. this->Tarjan(); @@ -17,8 +23,6 @@ cmComputeComponentGraph::cmComputeComponentGraph(Graph const& input) this->TransferEdges(); } -cmComputeComponentGraph::~cmComputeComponentGraph() = default; - void cmComputeComponentGraph::Tarjan() { int n = static_cast<int>(this->InputGraph.size()); diff --git a/Source/cmComputeComponentGraph.h b/Source/cmComputeComponentGraph.h index 202888c..b873131 100644 --- a/Source/cmComputeComponentGraph.h +++ b/Source/cmComputeComponentGraph.h @@ -31,6 +31,9 @@ public: cmComputeComponentGraph(Graph const& input); ~cmComputeComponentGraph(); + /** Run the computation. */ + void Compute(); + /** Get the adjacency list of the component graph. */ Graph const& GetComponentGraph() const { return this->ComponentGraph; } EdgeList const& GetComponentGraphEdges(int c) const diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index e9bf5a5..8ca2168 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -253,13 +253,13 @@ cmComputeLinkDepends::Compute() // Compute the final set of link entries. // Iterate in reverse order so we can keep only the last occurrence // of a shared library. - std::set<int> emmitted; + std::set<int> emitted; for (int i : cmReverseRange(this->FinalLinkOrder)) { LinkEntry const& e = this->EntryList[i]; cmGeneratorTarget const* t = e.Target; // Entries that we know the linker will re-use do not need to be repeated. bool uniquify = t && t->GetType() == cmStateEnums::SHARED_LIBRARY; - if (!uniquify || emmitted.insert(i).second) { + if (!uniquify || emitted.insert(i).second) { this->FinalLinkEntries.push_back(e); } } @@ -626,6 +626,7 @@ void cmComputeLinkDepends::OrderLinkEntires() // constraints disallow it. this->CCG = cm::make_unique<cmComputeComponentGraph>(this->EntryConstraintGraph); + this->CCG->Compute(); // The component graph is guaranteed to be acyclic. Start a DFS // from every entry to compute a topological order for the diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 4c5f57d..43cceae 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -515,7 +515,7 @@ bool cmComputeLinkInformation::Compute() // Restore the target link type so the correct system runtime // libraries are found. cmProp lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC"); - if (lss && cmIsOn(*lss)) { + if (cmIsOn(lss)) { this->SetCurrentLinkType(LinkStatic); } else { this->SetCurrentLinkType(this->StartLinkType); @@ -832,8 +832,7 @@ void cmComputeLinkInformation::ComputeLinkTypeInfo() // We can support link type switching only if all needed flags are // known. - if (static_link_type_flag && *static_link_type_flag && - shared_link_type_flag && *shared_link_type_flag) { + if (cmNonempty(static_link_type_flag) && cmNonempty(shared_link_type_flag)) { this->LinkTypeEnabled = true; this->StaticLinkTypeFlag = static_link_type_flag; this->SharedLinkTypeFlag = shared_link_type_flag; @@ -841,7 +840,7 @@ void cmComputeLinkInformation::ComputeLinkTypeInfo() // Lookup the starting link type from the target (linked statically?). cmProp lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC"); - this->StartLinkType = (lss && cmIsOn(*lss)) ? LinkStatic : LinkShared; + this->StartLinkType = cmIsOn(lss) ? LinkStatic : LinkShared; this->CurrentLinkType = this->StartLinkType; } @@ -849,31 +848,31 @@ void cmComputeLinkInformation::ComputeItemParserInfo() { // Get possible library name prefixes. cmMakefile* mf = this->Makefile; - this->AddLinkPrefix(mf->GetDefinition("CMAKE_STATIC_LIBRARY_PREFIX")); - this->AddLinkPrefix(mf->GetDefinition("CMAKE_SHARED_LIBRARY_PREFIX")); + this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX")); + this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_PREFIX")); // Import library names should be matched and treated as shared // libraries for the purposes of linking. - this->AddLinkExtension(mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), + this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), LinkShared); - this->AddLinkExtension(mf->GetDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"), + this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"), LinkStatic); - this->AddLinkExtension(mf->GetDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"), + this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"), LinkShared); - this->AddLinkExtension(mf->GetDefinition("CMAKE_LINK_LIBRARY_SUFFIX"), + this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX"), LinkUnknown); if (const char* linkSuffixes = mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) { std::vector<std::string> linkSuffixVec = cmExpandedList(linkSuffixes); for (std::string const& i : linkSuffixVec) { - this->AddLinkExtension(i.c_str(), LinkUnknown); + this->AddLinkExtension(i, LinkUnknown); } } if (const char* sharedSuffixes = mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) { std::vector<std::string> sharedSuffixVec = cmExpandedList(sharedSuffixes); for (std::string const& i : sharedSuffixVec) { - this->AddLinkExtension(i.c_str(), LinkShared); + this->AddLinkExtension(i, LinkShared); } } @@ -903,7 +902,7 @@ void cmComputeLinkInformation::ComputeItemParserInfo() #ifdef CM_COMPUTE_LINK_INFO_DEBUG fprintf(stderr, "any regex [%s]\n", reg_any.c_str()); #endif - this->ExtractAnyLibraryName.compile(reg_any.c_str()); + this->ExtractAnyLibraryName.compile(reg_any); // Create a regex to match static library names. if (!this->StaticLinkExtensions.empty()) { @@ -912,7 +911,7 @@ void cmComputeLinkInformation::ComputeItemParserInfo() #ifdef CM_COMPUTE_LINK_INFO_DEBUG fprintf(stderr, "static regex [%s]\n", reg_static.c_str()); #endif - this->ExtractStaticLibraryName.compile(reg_static.c_str()); + this->ExtractStaticLibraryName.compile(reg_static); } // Create a regex to match shared library names. @@ -924,20 +923,21 @@ void cmComputeLinkInformation::ComputeItemParserInfo() #ifdef CM_COMPUTE_LINK_INFO_DEBUG fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str()); #endif - this->ExtractSharedLibraryName.compile(reg_shared.c_str()); + this->ExtractSharedLibraryName.compile(reg_shared); } } -void cmComputeLinkInformation::AddLinkPrefix(const char* p) +void cmComputeLinkInformation::AddLinkPrefix(std::string const& p) { - if (p && *p) { + if (!p.empty()) { this->LinkPrefixes.insert(p); } } -void cmComputeLinkInformation::AddLinkExtension(const char* e, LinkType type) +void cmComputeLinkInformation::AddLinkExtension(std::string const& e, + LinkType type) { - if (e && *e) { + if (!e.empty()) { if (type == LinkStatic) { this->StaticLinkExtensions.emplace_back(e); } @@ -962,7 +962,7 @@ std::string cmComputeLinkInformation::CreateExtensionRegex( // Store this extension choice with the "." escaped. libext += "\\"; #if defined(_WIN32) && !defined(__CYGWIN__) - libext += this->NoCaseExpression(i.c_str()); + libext += this->NoCaseExpression(i); #else libext += i; #endif @@ -980,21 +980,19 @@ std::string cmComputeLinkInformation::CreateExtensionRegex( return libext; } -std::string cmComputeLinkInformation::NoCaseExpression(const char* str) +std::string cmComputeLinkInformation::NoCaseExpression(std::string const& str) { std::string ret; - ret.reserve(strlen(str) * 4); - const char* s = str; - while (*s) { - if (*s == '.') { - ret += *s; + ret.reserve(str.size() * 4); + for (char c : str) { + if (c == '.') { + ret += c; } else { ret += '['; - ret += static_cast<char>(tolower(*s)); - ret += static_cast<char>(toupper(*s)); + ret += static_cast<char>(tolower(c)); + ret += static_cast<char>(toupper(c)); ret += ']'; } - s++; } return ret; } @@ -1688,7 +1686,7 @@ void cmComputeLinkInformation::AddLibraryRuntimeInfo( } } -static void cmCLI_ExpandListUnique(const char* str, +static void cmCLI_ExpandListUnique(std::string const& str, std::vector<std::string>& out, std::set<std::string>& emitted) { @@ -1735,7 +1733,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, if (use_install_rpath) { std::string install_rpath; this->Target->GetInstallRPATH(this->Config, install_rpath); - cmCLI_ExpandListUnique(install_rpath.c_str(), runtimeDirs, emitted); + cmCLI_ExpandListUnique(install_rpath, runtimeDirs, emitted); } if (use_build_rpath) { // Add directories explicitly specified by user @@ -1743,7 +1741,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, if (this->Target->GetBuildRPATH(this->Config, build_rpath)) { // This will not resolve entries to use $ORIGIN, the user is expected to // do that if necessary. - cmCLI_ExpandListUnique(build_rpath.c_str(), runtimeDirs, emitted); + cmCLI_ExpandListUnique(build_rpath, runtimeDirs, emitted); } } if (use_build_rpath || use_link_rpath) { @@ -1769,7 +1767,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, std::string d = ri; if (!rootPath.empty() && cmHasPrefix(d, rootPath)) { d.erase(0, rootPath.size()); - } else if (stagePath && *stagePath && cmHasPrefix(d, stagePath)) { + } else if (cmNonempty(stagePath) && cmHasPrefix(d, stagePath)) { d.erase(0, strlen(stagePath)); d = cmStrCat(installPrefix, '/', d); cmSystemTools::ConvertToUnixSlashes(d); @@ -1800,7 +1798,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, std::string d = ri; if (!rootPath.empty() && cmHasPrefix(d, rootPath)) { d.erase(0, rootPath.size()); - } else if (stagePath && *stagePath && cmHasPrefix(d, stagePath)) { + } else if (cmNonempty(stagePath) && cmHasPrefix(d, stagePath)) { d.erase(0, strlen(stagePath)); d = cmStrCat(installPrefix, '/', d); cmSystemTools::ConvertToUnixSlashes(d); @@ -1823,8 +1821,8 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, "CMAKE_" + li + "_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH"; if (this->Makefile->IsOn(useVar)) { std::string dirVar = "CMAKE_" + li + "_IMPLICIT_LINK_DIRECTORIES"; - if (const char* dirs = this->Makefile->GetDefinition(dirVar)) { - cmCLI_ExpandListUnique(dirs, runtimeDirs, emitted); + if (cmProp dirs = this->Makefile->GetDef(dirVar)) { + cmCLI_ExpandListUnique(*dirs, runtimeDirs, emitted); } } } @@ -1832,7 +1830,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, // Add runtime paths required by the platform to always be // present. This is done even when skipping rpath support. - cmCLI_ExpandListUnique(this->RuntimeAlways.c_str(), runtimeDirs, emitted); + cmCLI_ExpandListUnique(this->RuntimeAlways, runtimeDirs, emitted); } std::string cmComputeLinkInformation::GetRPathString(bool for_install) const diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index e50d369..544ff23 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -144,11 +144,11 @@ private: cmsys::RegularExpression ExtractSharedLibraryName; cmsys::RegularExpression ExtractAnyLibraryName; std::string SharedRegexString; - void AddLinkPrefix(const char* p); - void AddLinkExtension(const char* e, LinkType type); + void AddLinkPrefix(std::string const& p); + void AddLinkExtension(std::string const& e, LinkType type); std::string CreateExtensionRegex(std::vector<std::string> const& exts, LinkType type); - std::string NoCaseExpression(const char* str); + std::string NoCaseExpression(std::string const& str); // Handling of link items. void AddTargetItem(BT<std::string> const& item, diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 41f5346..1f22ce6 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -17,10 +17,12 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmSourceFile.h" #include "cmState.h" #include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" #include "cmTargetDepend.h" @@ -115,18 +117,32 @@ bool cmComputeTargetDepends::Compute() if (this->DebugMode) { this->DisplayGraph(this->InitialGraph, "initial"); } + cmComputeComponentGraph ccg1(this->InitialGraph); + ccg1.Compute(); + if (!this->CheckComponents(ccg1)) { + return false; + } + + // Compute the intermediate graph. + this->CollectSideEffects(); + this->ComputeIntermediateGraph(); + if (this->DebugMode) { + this->DisplaySideEffects(); + this->DisplayGraph(this->IntermediateGraph, "intermediate"); + } // Identify components. - cmComputeComponentGraph ccg(this->InitialGraph); + cmComputeComponentGraph ccg2(this->IntermediateGraph); + ccg2.Compute(); if (this->DebugMode) { - this->DisplayComponents(ccg); + this->DisplayComponents(ccg2, "intermediate"); } - if (!this->CheckComponents(ccg)) { + if (!this->CheckComponents(ccg2)) { return false; } // Compute the final dependency graph. - if (!this->ComputeFinalDepends(ccg)) { + if (!this->ComputeFinalDepends(ccg2)) { return false; } if (this->DebugMode) { @@ -184,7 +200,7 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) { // Get the depender. cmGeneratorTarget const* depender = this->Targets[depender_index]; - if (depender->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!depender->IsInBuildSystem()) { return; } @@ -196,18 +212,20 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) std::set<cmLinkItem> emitted; std::vector<std::string> const& configs = - depender->Makefile->GetGeneratorConfigs(); + depender->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); 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); + + if (cmLinkImplementation const* impl = + depender->GetLinkImplementation(it)) { + 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); + } } } @@ -356,10 +374,9 @@ void cmComputeTargetDepends::AddTargetDepend( int depender_index, cmGeneratorTarget const* dependee, cmListFileBacktrace const& dependee_backtrace, bool linking, bool cross) { - if (dependee->IsImported() || - dependee->GetType() == cmStateEnums::INTERFACE_LIBRARY) { - // Skip IMPORTED and INTERFACE targets but follow their utility - // dependencies. + if (!dependee->IsInBuildSystem()) { + // Skip targets that are not in the buildsystem but follow their + // utility dependencies. std::set<cmLinkItem> const& utils = dependee->GetUtilityItems(); for (cmLinkItem const& i : utils) { if (cmGeneratorTarget const* transitive_dependee = i.Target) { @@ -380,6 +397,111 @@ void cmComputeTargetDepends::AddTargetDepend( } } +void cmComputeTargetDepends::CollectSideEffects() +{ + this->SideEffects.resize(0); + this->SideEffects.resize(this->InitialGraph.size()); + + int n = static_cast<int>(this->InitialGraph.size()); + std::set<int> visited; + for (int i = 0; i < n; ++i) { + this->CollectSideEffectsForTarget(visited, i); + } +} + +void cmComputeTargetDepends::CollectSideEffectsForTarget( + std::set<int>& visited, int depender_index) +{ + if (!visited.count(depender_index)) { + auto& se = this->SideEffects[depender_index]; + visited.insert(depender_index); + this->Targets[depender_index]->AppendCustomCommandSideEffects( + se.CustomCommandSideEffects); + this->Targets[depender_index]->AppendLanguageSideEffects( + se.LanguageSideEffects); + + for (auto const& edge : this->InitialGraph[depender_index]) { + this->CollectSideEffectsForTarget(visited, edge); + auto const& dse = this->SideEffects[edge]; + se.CustomCommandSideEffects.insert(dse.CustomCommandSideEffects.cbegin(), + dse.CustomCommandSideEffects.cend()); + for (auto const& it : dse.LanguageSideEffects) { + se.LanguageSideEffects[it.first].insert(it.second.cbegin(), + it.second.cend()); + } + } + } +} + +void cmComputeTargetDepends::ComputeIntermediateGraph() +{ + this->IntermediateGraph.resize(0); + this->IntermediateGraph.resize(this->InitialGraph.size()); + + int n = static_cast<int>(this->InitialGraph.size()); + for (int i = 0; i < n; ++i) { + auto const& initialEdges = this->InitialGraph[i]; + auto& intermediateEdges = this->IntermediateGraph[i]; + cmGeneratorTarget const* gt = this->Targets[i]; + if (gt->GetType() != cmStateEnums::STATIC_LIBRARY && + gt->GetType() != cmStateEnums::OBJECT_LIBRARY) { + intermediateEdges = initialEdges; + } else { + if (cmProp optimizeDependencies = + gt->GetProperty("OPTIMIZE_DEPENDENCIES")) { + if (cmIsOn(optimizeDependencies)) { + this->OptimizeLinkDependencies(gt, intermediateEdges, initialEdges); + } else { + intermediateEdges = initialEdges; + } + } else { + intermediateEdges = initialEdges; + } + } + } +} + +void cmComputeTargetDepends::OptimizeLinkDependencies( + cmGeneratorTarget const* gt, cmGraphEdgeList& outputEdges, + cmGraphEdgeList const& inputEdges) +{ + std::set<int> emitted; + for (auto const& edge : inputEdges) { + if (edge.IsStrong()) { + // Preserve strong edges + outputEdges.push_back(edge); + } else { + auto const& dse = this->SideEffects[edge]; + + // Add edges that have custom command side effects + for (cmGeneratorTarget const* dep : dse.CustomCommandSideEffects) { + auto index = this->TargetIndex[dep]; + if (!emitted.count(index)) { + emitted.insert(index); + outputEdges.push_back( + cmGraphEdge(index, false, edge.IsCross(), edge.GetBacktrace())); + } + } + + // Add edges that have language side effects for languages we + // care about + for (auto const& lang : gt->GetAllConfigCompileLanguages()) { + auto it = dse.LanguageSideEffects.find(lang); + if (it != dse.LanguageSideEffects.end()) { + for (cmGeneratorTarget const* dep : it->second) { + auto index = this->TargetIndex[dep]; + if (!emitted.count(index)) { + emitted.insert(index); + outputEdges.push_back(cmGraphEdge(index, false, edge.IsCross(), + edge.GetBacktrace())); + } + } + } + } + } + } +} + void cmComputeTargetDepends::DisplayGraph(Graph const& graph, const std::string& name) { @@ -400,10 +522,39 @@ void cmComputeTargetDepends::DisplayGraph(Graph const& graph, fprintf(stderr, "\n"); } +void cmComputeTargetDepends::DisplaySideEffects() +{ + fprintf(stderr, "The side effects are:\n"); + int n = static_cast<int>(SideEffects.size()); + for (int depender_index = 0; depender_index < n; ++depender_index) { + cmGeneratorTarget const* depender = this->Targets[depender_index]; + fprintf(stderr, "target %d is [%s]\n", depender_index, + depender->GetName().c_str()); + if (!this->SideEffects[depender_index].CustomCommandSideEffects.empty()) { + fprintf(stderr, " custom commands\n"); + for (auto const* gt : + this->SideEffects[depender_index].CustomCommandSideEffects) { + fprintf(stderr, " from target %d [%s]\n", this->TargetIndex[gt], + gt->GetName().c_str()); + } + } + for (auto const& it : + this->SideEffects[depender_index].LanguageSideEffects) { + fprintf(stderr, " language %s\n", it.first.c_str()); + for (auto const* gt : it.second) { + fprintf(stderr, " from target %d [%s]\n", this->TargetIndex[gt], + gt->GetName().c_str()); + } + } + } + fprintf(stderr, "\n"); +} + void cmComputeTargetDepends::DisplayComponents( - cmComputeComponentGraph const& ccg) + cmComputeComponentGraph const& ccg, const std::string& name) { - fprintf(stderr, "The strongly connected components are:\n"); + fprintf(stderr, "The strongly connected components for the %s graph are:\n", + name.c_str()); std::vector<NodeList> const& components = ccg.GetComponents(); int n = static_cast<int>(components.size()); for (int c = 0; c < n; ++c) { diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h index e0d625f..277521d 100644 --- a/Source/cmComputeTargetDepends.h +++ b/Source/cmComputeTargetDepends.h @@ -42,6 +42,13 @@ public: cmTargetDependSet& deps); private: + struct TargetSideEffects + { + std::set<cmGeneratorTarget const*> CustomCommandSideEffects; + std::map<std::string, std::set<cmGeneratorTarget const*>> + LanguageSideEffects; + }; + void CollectTargets(); void CollectDepends(); void CollectTargetDepends(int depender_index); @@ -50,6 +57,12 @@ private: void AddTargetDepend(int depender_index, cmGeneratorTarget const* dependee, cmListFileBacktrace const& dependee_backtrace, bool linking, bool cross); + void CollectSideEffects(); + void CollectSideEffectsForTarget(std::set<int>& visited, int depender_index); + void ComputeIntermediateGraph(); + void OptimizeLinkDependencies(cmGeneratorTarget const* gt, + cmGraphEdgeList& outputEdges, + cmGraphEdgeList const& inputEdges); bool ComputeFinalDepends(cmComputeComponentGraph const& ccg); void AddInterfaceDepends(int depender_index, cmLinkItem const& dependee_name, const std::string& config, @@ -74,11 +87,15 @@ private: using EdgeList = cmGraphEdgeList; using Graph = cmGraphAdjacencyList; Graph InitialGraph; + Graph IntermediateGraph; Graph FinalGraph; + std::vector<TargetSideEffects> SideEffects; void DisplayGraph(Graph const& graph, const std::string& name); + void DisplaySideEffects(); // Deal with connected components. - void DisplayComponents(cmComputeComponentGraph const& ccg); + void DisplayComponents(cmComputeComponentGraph const& ccg, + const std::string& name); bool CheckComponents(cmComputeComponentGraph const& ccg); void ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, int c, bool strong = false); diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index 4de1c5d..97e7856 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -19,7 +19,6 @@ #cmakedefine HAVE_UNSETENV #cmakedefine CMAKE_USE_ELF_PARSER #cmakedefine CMAKE_USE_MACH_PARSER -#cmakedefine CMake_HAVE_CXX_MAKE_UNIQUE #define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@ #define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@" #define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@" diff --git a/Source/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx index 5b3045d..68322cc 100644 --- a/Source/cmConfigureFileCommand.cxx +++ b/Source/cmConfigureFileCommand.cxx @@ -60,6 +60,7 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args, } bool copyOnly = false; bool escapeQuotes = false; + bool use_source_permissions = true; static std::set<cm::string_view> noopOptions = { /* Legacy. */ @@ -87,6 +88,8 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args, escapeQuotes = true; } else if (args[i] == "@ONLY") { atOnly = true; + } else if (args[i] == "NO_SOURCE_PERMISSIONS") { + use_source_permissions = false; } else if (noopOptions.find(args[i]) != noopOptions.end()) { /* Ignore no-op options. */ } else { @@ -102,7 +105,8 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args, } if (!status.GetMakefile().ConfigureFile( - inputFile, outputFile, copyOnly, atOnly, escapeQuotes, newLineStyle)) { + inputFile, outputFile, copyOnly, atOnly, escapeQuotes, + use_source_permissions, newLineStyle)) { status.SetError("Problem configuring file"); return false; } diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 8550d04..63c1484 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -18,6 +18,7 @@ #include "cmMessageType.h" #include "cmOutputConverter.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -25,77 +26,205 @@ #include "cmVersion.h" #include "cmake.h" -static std::string const kCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN = - "CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN"; -static std::string const kCMAKE_C_COMPILER_TARGET = "CMAKE_C_COMPILER_TARGET"; -static std::string const kCMAKE_C_LINK_NO_PIE_SUPPORTED = - "CMAKE_C_LINK_NO_PIE_SUPPORTED"; -static std::string const kCMAKE_C_LINK_PIE_SUPPORTED = - "CMAKE_C_LINK_PIE_SUPPORTED"; -static std::string const kCMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN = - "CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN"; -static std::string const kCMAKE_CXX_COMPILER_TARGET = - "CMAKE_CXX_COMPILER_TARGET"; -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"; -static std::string const kCMAKE_LINK_SEARCH_END_STATIC = +namespace { +class LanguageStandardState +{ +public: + LanguageStandardState(std::string&& lang) + : IsEnabled(false) + , DidStandard(false) + , DidStandardRequired(false) + , DidExtensions(false) + , StandardFlag(lang + "_STANDARD") + , RequiredFlag(lang + "_STANDARD_REQUIRED") + , ExtensionFlag(lang + "_EXTENSIONS") + { + } + + void Enabled(bool isEnabled) { this->IsEnabled = isEnabled; } + + bool UpdateIfMatches(std::vector<std::string> const& argv, size_t& index) + { + bool updated = false; + if (argv[index] == this->StandardFlag) { + this->DidStandard = true; + this->StandardValue = argv[++index]; + updated = true; + } else if (argv[index] == this->RequiredFlag) { + this->DidStandardRequired = true; + this->RequiredValue = argv[++index]; + updated = true; + } else if (argv[index] == this->ExtensionFlag) { + this->DidExtensions = true; + this->ExtensionValue = argv[++index]; + updated = true; + } + return updated; + } + + bool Validate(cmMakefile* const makefile) const + { + if (this->DidStandard) { + makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->StandardFlag, + " allowed only in source file signature.")); + return false; + } + if (this->DidStandardRequired) { + makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->RequiredFlag, + " allowed only in source file signature.")); + return false; + } + if (this->DidExtensions) { + makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(this->ExtensionFlag, + " allowed only in source file signature.")); + return false; + } + + return true; + } + + bool DidNone() const + { + return !this->DidStandard && !this->DidStandardRequired && + !this->DidExtensions; + } + + void LoadUnsetPropertyValues(cmMakefile* const makefile, bool honorStandard, + bool warnCMP0067, + std::vector<std::string>& warnCMP0067Variables) + { + if (!this->IsEnabled) { + return; + } + + auto lookupStdVar = [&](std::string const& var) -> std::string { + std::string value = makefile->GetSafeDefinition(var); + if (warnCMP0067 && !value.empty()) { + value.clear(); + warnCMP0067Variables.push_back(var); + } + return value; + }; + + if (honorStandard || warnCMP0067) { + if (!this->DidStandard) { + this->StandardValue = + lookupStdVar(cmStrCat("CMAKE_", this->StandardFlag)); + } + if (!this->DidStandardRequired) { + this->RequiredValue = + lookupStdVar(cmStrCat("CMAKE_", this->RequiredFlag)); + } + if (!this->DidExtensions) { + this->ExtensionValue = + lookupStdVar(cmStrCat("CMAKE_", this->ExtensionFlag)); + } + } + } + + void WriteProperties(FILE* fout, std::string const& targetName) const + { + if (!this->IsEnabled) { + return; + } + + auto writeProp = [&](std::string const& prop, std::string const& value) { + fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n", + targetName.c_str(), + cmOutputConverter::EscapeForCMake(prop).c_str(), + cmOutputConverter::EscapeForCMake(value).c_str()); + }; + + if (!this->StandardValue.empty()) { + writeProp(this->StandardFlag, this->StandardValue); + } + if (!this->RequiredValue.empty()) { + writeProp(this->RequiredFlag, this->RequiredValue); + } + if (!this->ExtensionValue.empty()) { + writeProp(this->ExtensionFlag, this->ExtensionValue); + } + } + +private: + bool IsEnabled; + bool DidStandard; + bool DidStandardRequired; + bool DidExtensions; + + std::string StandardFlag; + std::string RequiredFlag; + std::string ExtensionFlag; + + std::string StandardValue; + std::string RequiredValue; + std::string ExtensionValue; +}; + +constexpr size_t lang_property_start = 0; +constexpr size_t lang_property_size = 4; +constexpr size_t pie_property_start = 4; +constexpr size_t pie_property_size = 2; +#define SETUP_LANGUAGE(name, lang) \ + static const std::string name[lang_property_size + pie_property_size + 1] = \ + { "CMAKE_" #lang "_COMPILER_EXTERNAL_TOOLCHAIN", \ + "CMAKE_" #lang "_COMPILER_TARGET", \ + "CMAKE_" #lang "_LINK_NO_PIE_SUPPORTED", \ + "CMAKE_" #lang "_PIE_SUPPORTED", "" } + +// NOLINTNEXTLINE(bugprone-suspicious-missing-comma) +SETUP_LANGUAGE(c_properties, C); +// NOLINTNEXTLINE(bugprone-suspicious-missing-comma) +SETUP_LANGUAGE(cxx_properties, CXX); + +// NOLINTNEXTLINE(bugprone-suspicious-missing-comma) +SETUP_LANGUAGE(cuda_properties, CUDA); +// NOLINTNEXTLINE(bugprone-suspicious-missing-comma) +SETUP_LANGUAGE(fortran_properties, Fortran); +// NOLINTNEXTLINE(bugprone-suspicious-missing-comma) +SETUP_LANGUAGE(objc_properties, OBJC); +// NOLINTNEXTLINE(bugprone-suspicious-missing-comma) +SETUP_LANGUAGE(objcxx_properties, OBJCXX); +// NOLINTNEXTLINE(bugprone-suspicious-missing-comma) +SETUP_LANGUAGE(swift_properties, Swift); +#undef SETUP_LANGUAGE + +std::string const kCMAKE_CUDA_ARCHITECTURES = "CMAKE_CUDA_ARCHITECTURES"; +std::string const kCMAKE_CUDA_RUNTIME_LIBRARY = "CMAKE_CUDA_RUNTIME_LIBRARY"; +std::string const kCMAKE_ENABLE_EXPORTS = "CMAKE_ENABLE_EXPORTS"; +std::string const kCMAKE_LINK_SEARCH_END_STATIC = "CMAKE_LINK_SEARCH_END_STATIC"; -static std::string const kCMAKE_LINK_SEARCH_START_STATIC = +std::string const kCMAKE_LINK_SEARCH_START_STATIC = "CMAKE_LINK_SEARCH_START_STATIC"; -static std::string const kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT = +std::string const kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT = "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT"; -static std::string const kCMAKE_OSX_ARCHITECTURES = "CMAKE_OSX_ARCHITECTURES"; -static std::string const kCMAKE_OSX_DEPLOYMENT_TARGET = - "CMAKE_OSX_DEPLOYMENT_TARGET"; -static std::string const kCMAKE_OSX_SYSROOT = "CMAKE_OSX_SYSROOT"; -static std::string const kCMAKE_APPLE_ARCH_SYSROOTS = - "CMAKE_APPLE_ARCH_SYSROOTS"; -static std::string const kCMAKE_POSITION_INDEPENDENT_CODE = +std::string const kCMAKE_OSX_ARCHITECTURES = "CMAKE_OSX_ARCHITECTURES"; +std::string const kCMAKE_OSX_DEPLOYMENT_TARGET = "CMAKE_OSX_DEPLOYMENT_TARGET"; +std::string const kCMAKE_OSX_SYSROOT = "CMAKE_OSX_SYSROOT"; +std::string const kCMAKE_APPLE_ARCH_SYSROOTS = "CMAKE_APPLE_ARCH_SYSROOTS"; +std::string const kCMAKE_POSITION_INDEPENDENT_CODE = "CMAKE_POSITION_INDEPENDENT_CODE"; -static std::string const kCMAKE_SYSROOT = "CMAKE_SYSROOT"; -static std::string const kCMAKE_SYSROOT_COMPILE = "CMAKE_SYSROOT_COMPILE"; -static std::string const kCMAKE_SYSROOT_LINK = "CMAKE_SYSROOT_LINK"; -static std::string const kCMAKE_Swift_COMPILER_TARGET = - "CMAKE_Swift_COMPILER_TARGET"; -static std::string const kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES = +std::string const kCMAKE_SYSROOT = "CMAKE_SYSROOT"; +std::string const kCMAKE_SYSROOT_COMPILE = "CMAKE_SYSROOT_COMPILE"; +std::string const kCMAKE_SYSROOT_LINK = "CMAKE_SYSROOT_LINK"; +std::string const kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES = "CMAKE_TRY_COMPILE_OSX_ARCHITECTURES"; -static std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES = +std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES = "CMAKE_TRY_COMPILE_PLATFORM_VARIABLES"; -static std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED"; +std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED"; /* GHS Multi platform variables */ -static std::set<std::string> ghs_platform_vars{ +std::set<std::string> const ghs_platform_vars{ "GHS_TARGET_PLATFORM", "GHS_PRIMARY_TARGET", "GHS_TOOLSET_ROOT", "GHS_OS_ROOT", "GHS_OS_DIR", "GHS_BSP_NAME", "GHS_OS_DIR_OPTION" }; - -static void writeProperty(FILE* fout, std::string const& targetName, - std::string const& prop, std::string const& value) -{ - fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n", targetName.c_str(), - cmOutputConverter::EscapeForCMake(prop).c_str(), - cmOutputConverter::EscapeForCMake(value).c_str()); -} - -std::string cmCoreTryCompile::LookupStdVar(std::string const& var, - bool warnCMP0067) -{ - std::string value = this->Makefile->GetSafeDefinition(var); - if (warnCMP0067 && !value.empty()) { - value.clear(); - this->WarnCMP0067.push_back(var); - } - return value; } int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, @@ -107,9 +236,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, this->SrcFileSignature = true; cmStateEnums::TargetType targetType = cmStateEnums::EXECUTABLE; - const std::string* tt = - this->Makefile->GetDef("CMAKE_TRY_COMPILE_TARGET_TYPE"); - if (!isTryRun && tt && !tt->empty()) { + cmProp tt = this->Makefile->GetDef("CMAKE_TRY_COMPILE_TARGET_TYPE"); + if (!isTryRun && cmNonempty(tt)) { if (*tt == cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) { targetType = cmStateEnums::EXECUTABLE; } else if (*tt == @@ -137,21 +265,11 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, std::string outputVariable; std::string copyFile; std::string copyFileError; - std::string cStandard; - std::string objcStandard; - std::string cxxStandard; - std::string objcxxStandard; - std::string cudaStandard; - std::string cStandardRequired; - std::string cxxStandardRequired; - std::string objcStandardRequired; - std::string objcxxStandardRequired; - std::string cudaStandardRequired; - std::string cExtensions; - std::string cxxExtensions; - std::string objcExtensions; - std::string objcxxExtensions; - std::string cudaExtensions; + LanguageStandardState cState("C"); + LanguageStandardState cudaState("CUDA"); + LanguageStandardState cxxState("CXX"); + LanguageStandardState objcState("OBJC"); + LanguageStandardState objcxxState("OBJCXX"); std::vector<std::string> targets; std::vector<std::string> linkOptions; std::string libsToLink = " "; @@ -160,21 +278,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, bool didOutputVariable = false; bool didCopyFile = false; bool didCopyFileError = false; - bool didCStandard = false; - bool didCxxStandard = false; - bool didObjCStandard = false; - bool didObjCxxStandard = false; - bool didCudaStandard = false; - bool didCStandardRequired = false; - bool didCxxStandardRequired = false; - bool didObjCStandardRequired = false; - bool didObjCxxStandardRequired = false; - bool didCudaStandardRequired = false; - bool didCExtensions = false; - bool didCxxExtensions = false; - bool didObjCExtensions = false; - bool didObjCxxExtensions = false; - bool didCudaExtensions = false; bool useSources = argv[2] == "SOURCES"; std::vector<std::string> sources; @@ -188,21 +291,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, DoingOutputVariable, DoingCopyFile, DoingCopyFileError, - DoingCStandard, - DoingCxxStandard, - DoingObjCStandard, - DoingObjCxxStandard, - DoingCudaStandard, - DoingCStandardRequired, - DoingCxxStandardRequired, - DoingObjCStandardRequired, - DoingObjCxxStandardRequired, - DoingCudaStandardRequired, - DoingCExtensions, - DoingCxxExtensions, - DoingObjCExtensions, - DoingObjCxxExtensions, - DoingCudaExtensions, DoingSources, DoingCMakeInternal }; @@ -226,51 +314,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } else if (argv[i] == "COPY_FILE_ERROR") { doing = DoingCopyFileError; didCopyFileError = true; - } else if (argv[i] == "C_STANDARD") { - doing = DoingCStandard; - didCStandard = true; - } else if (argv[i] == "CXX_STANDARD") { - doing = DoingCxxStandard; - didCxxStandard = true; - } else if (argv[i] == "OBJC_STANDARD") { - doing = DoingObjCStandard; - didObjCStandard = true; - } else if (argv[i] == "OBJCXX_STANDARD") { - doing = DoingObjCxxStandard; - didObjCxxStandard = true; - } else if (argv[i] == "CUDA_STANDARD") { - doing = DoingCudaStandard; - didCudaStandard = true; - } else if (argv[i] == "C_STANDARD_REQUIRED") { - doing = DoingCStandardRequired; - didCStandardRequired = true; - } else if (argv[i] == "CXX_STANDARD_REQUIRED") { - doing = DoingCxxStandardRequired; - didCxxStandardRequired = true; - } else if (argv[i] == "OBJC_STANDARD_REQUIRED") { - doing = DoingObjCStandardRequired; - didObjCStandardRequired = true; - } else if (argv[i] == "OBJCXX_STANDARD_REQUIRED") { - doing = DoingObjCxxStandardRequired; - didObjCxxStandardRequired = true; - } else if (argv[i] == "CUDA_STANDARD_REQUIRED") { - doing = DoingCudaStandardRequired; - didCudaStandardRequired = true; - } else if (argv[i] == "C_EXTENSIONS") { - doing = DoingCExtensions; - didCExtensions = true; - } else if (argv[i] == "CXX_EXTENSIONS") { - doing = DoingCxxExtensions; - didCxxExtensions = true; - } else if (argv[i] == "OBJC_EXTENSIONS") { - doing = DoingObjCExtensions; - didObjCExtensions = true; - } else if (argv[i] == "OBJCXX_EXTENSIONS") { - doing = DoingObjCxxExtensions; - didObjCxxExtensions = true; - } else if (argv[i] == "CUDA_EXTENSIONS") { - doing = DoingCudaExtensions; - didCudaExtensions = true; + } else if (cState.UpdateIfMatches(argv, i) || + cxxState.UpdateIfMatches(argv, i) || + cudaState.UpdateIfMatches(argv, i) || + objcState.UpdateIfMatches(argv, i) || + objcxxState.UpdateIfMatches(argv, i)) { + continue; } else if (argv[i] == "__CMAKE_INTERNAL") { doing = DoingCMakeInternal; } else if (doing == DoingCMakeFlags) { @@ -315,51 +364,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } else if (doing == DoingCopyFileError) { copyFileError = argv[i]; doing = DoingNone; - } else if (doing == DoingCStandard) { - cStandard = argv[i]; - doing = DoingNone; - } else if (doing == DoingCxxStandard) { - cxxStandard = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCStandard) { - objcStandard = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCxxStandard) { - objcxxStandard = argv[i]; - doing = DoingNone; - } else if (doing == DoingCudaStandard) { - cudaStandard = argv[i]; - doing = DoingNone; - } else if (doing == DoingCStandardRequired) { - cStandardRequired = argv[i]; - doing = DoingNone; - } else if (doing == DoingCxxStandardRequired) { - cxxStandardRequired = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCStandardRequired) { - objcStandardRequired = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCxxStandardRequired) { - objcxxStandardRequired = argv[i]; - doing = DoingNone; - } else if (doing == DoingCudaStandardRequired) { - cudaStandardRequired = argv[i]; - doing = DoingNone; - } else if (doing == DoingCExtensions) { - cExtensions = argv[i]; - doing = DoingNone; - } else if (doing == DoingCxxExtensions) { - cxxExtensions = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCExtensions) { - objcExtensions = argv[i]; - doing = DoingNone; - } else if (doing == DoingObjCxxExtensions) { - objcxxExtensions = argv[i]; - doing = DoingNone; - } else if (doing == DoingCudaExtensions) { - cudaExtensions = argv[i]; - doing = DoingNone; } else if (doing == DoingSources) { sources.push_back(argv[i]); } else if (doing == DoingCMakeInternal) { @@ -411,59 +415,22 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, return -1; } - if (didCStandard && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "C_STANDARD allowed only in source file signature."); - return -1; - } - if (didCxxStandard && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CXX_STANDARD allowed only in source file signature."); - return -1; - } - if (didCudaStandard && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CUDA_STANDARD allowed only in source file signature."); - return -1; - } - if (didCStandardRequired && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "C_STANDARD_REQUIRED allowed only in source file signature."); - return -1; - } - if (didCxxStandardRequired && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CXX_STANDARD_REQUIRED allowed only in source file signature."); - return -1; - } - if (didCudaStandardRequired && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CUDA_STANDARD_REQUIRED allowed only in source file signature."); - return -1; - } - if (didCExtensions && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "C_EXTENSIONS allowed only in source file signature."); - return -1; - } - if (didCxxExtensions && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CXX_EXTENSIONS allowed only in source file signature."); - return -1; - } - if (didCudaExtensions && !this->SrcFileSignature) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - "CUDA_EXTENSIONS allowed only in source file signature."); - return -1; + if (!this->SrcFileSignature) { + if (!cState.Validate(this->Makefile)) { + return -1; + } + if (!cudaState.Validate(this->Makefile)) { + return -1; + } + if (!cxxState.Validate(this->Makefile)) { + return -1; + } + if (!objcState.Validate(this->Makefile)) { + return -1; + } + if (!objcxxState.Validate(this->Makefile)) { + return -1; + } } // compute the binary dir when TRY_COMPILE is called with a src file @@ -721,12 +688,23 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, // Forward a set of variables to the inner project cache. { std::set<std::string> vars; - vars.insert(kCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN); - vars.insert(kCMAKE_C_COMPILER_TARGET); - vars.insert(kCMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN); - vars.insert(kCMAKE_CXX_COMPILER_TARGET); + vars.insert(&c_properties[lang_property_start], + &c_properties[lang_property_start + lang_property_size]); + vars.insert(&cxx_properties[lang_property_start], + &cxx_properties[lang_property_start + lang_property_size]); + vars.insert(&cuda_properties[lang_property_start], + &cuda_properties[lang_property_start + lang_property_size]); + vars.insert( + &fortran_properties[lang_property_start], + &fortran_properties[lang_property_start + lang_property_size]); + vars.insert(&objc_properties[lang_property_start], + &objc_properties[lang_property_start + lang_property_size]); + vars.insert( + &objcxx_properties[lang_property_start], + &objcxx_properties[lang_property_start + lang_property_size]); + vars.insert(&swift_properties[lang_property_start], + &swift_properties[lang_property_start + lang_property_size]); 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); @@ -739,7 +717,6 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, vars.insert(kCMAKE_SYSROOT); vars.insert(kCMAKE_SYSROOT_COMPILE); vars.insert(kCMAKE_SYSROOT_LINK); - vars.insert(kCMAKE_Swift_COMPILER_TARGET); vars.insert(kCMAKE_WARN_DEPRECATED); vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s); @@ -753,10 +730,22 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, cmPolicies::NEW) { // To ensure full support of PIE, propagate cache variables // driving the link options - vars.insert(kCMAKE_C_LINK_PIE_SUPPORTED); - vars.insert(kCMAKE_C_LINK_NO_PIE_SUPPORTED); - vars.insert(kCMAKE_CXX_LINK_PIE_SUPPORTED); - vars.insert(kCMAKE_CXX_LINK_NO_PIE_SUPPORTED); + vars.insert(&c_properties[pie_property_start], + &c_properties[pie_property_start + pie_property_size]); + vars.insert(&cxx_properties[pie_property_start], + &cxx_properties[pie_property_start + pie_property_size]); + vars.insert(&cuda_properties[pie_property_start], + &cuda_properties[pie_property_start + pie_property_size]); + vars.insert( + &fortran_properties[pie_property_start], + &fortran_properties[pie_property_start + pie_property_size]); + vars.insert(&objc_properties[pie_property_start], + &objc_properties[pie_property_start + pie_property_size]); + vars.insert( + &objcxx_properties[pie_property_start], + &objcxx_properties[pie_property_start + pie_property_size]); + vars.insert(&swift_properties[pie_property_start], + &swift_properties[pie_property_start + pie_property_size]); } /* for the TRY_COMPILEs we want to be able to specify the architecture. @@ -819,21 +808,17 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } fprintf(fout, ")\n"); - bool const testC = testLangs.find("C") != testLangs.end(); - bool const testObjC = testLangs.find("OBJC") != testLangs.end(); - bool const testCxx = testLangs.find("CXX") != testLangs.end(); - bool const testObjCxx = testLangs.find("OBJCXX") != testLangs.end(); - bool const testCuda = testLangs.find("CUDA") != testLangs.end(); + cState.Enabled(testLangs.find("C") != testLangs.end()); + cxxState.Enabled(testLangs.find("CXX") != testLangs.end()); + cudaState.Enabled(testLangs.find("CUDA") != testLangs.end()); + objcState.Enabled(testLangs.find("OBJC") != testLangs.end()); + objcxxState.Enabled(testLangs.find("OBJCXX") != testLangs.end()); bool warnCMP0067 = false; bool honorStandard = true; - if (!didCStandard && !didCxxStandard && !didObjCStandard && - !didObjCxxStandard && !didCudaStandard && !didCStandardRequired && - !didCxxStandardRequired && !didObjCStandardRequired && - !didObjCxxStandardRequired && !didCudaStandardRequired && - !didCExtensions && !didCxxExtensions && !didObjCExtensions && - !didObjCxxExtensions && !didCudaExtensions) { + if (cState.DidNone() && cxxState.DidNone() && objcState.DidNone() && + objcxxState.DidNone() && cudaState.DidNone()) { switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0067)) { case cmPolicies::WARN: warnCMP0067 = this->Makefile->PolicyOptionalWarningEnabled( @@ -855,46 +840,20 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } } - if (honorStandard || warnCMP0067) { + std::vector<std::string> warnCMP0067Variables; - auto testLanguage = - [&](bool testLang, bool didLangStandard, bool didLangStandardRequired, - bool didLangExtensions, std::string& langStandard, - std::string& langStandardRequired, std::string& langExtensions, - const std::string& lang) { - if (testLang) { - if (!didLangStandard) { - langStandard = this->LookupStdVar( - cmStrCat("CMAKE_", lang, "_STANDARD"), warnCMP0067); - } - if (!didLangStandardRequired) { - langStandardRequired = this->LookupStdVar( - cmStrCat("CMAKE_", lang, "_STANDARD_REQUIRED"), warnCMP0067); - } - if (!didLangExtensions) { - langExtensions = this->LookupStdVar( - cmStrCat("CMAKE_", lang, "_EXTENSIONS"), warnCMP0067); - } - } - }; - - testLanguage(testC, didCStandard, didCStandardRequired, didCExtensions, - cStandard, cStandardRequired, cExtensions, "C"); - testLanguage(testObjC, didObjCStandard, didObjCStandardRequired, - didObjCExtensions, objcStandard, objcStandardRequired, - objcExtensions, "OBJC"); - testLanguage(testCxx, didCxxStandard, didCxxStandardRequired, - didCxxExtensions, cxxStandard, cxxStandardRequired, - cxxExtensions, "CXX"); - testLanguage(testObjCxx, didObjCxxStandard, didObjCxxStandardRequired, - didObjCxxExtensions, objcxxStandard, objcxxStandardRequired, - objcxxExtensions, "OBJCXX"); - testLanguage(testCuda, didCudaStandard, didCudaStandardRequired, - didCudaExtensions, cudaStandard, cudaStandardRequired, - cudaExtensions, "CUDA"); - } + cState.LoadUnsetPropertyValues(this->Makefile, honorStandard, warnCMP0067, + warnCMP0067Variables); + cxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard, + warnCMP0067, warnCMP0067Variables); + cudaState.LoadUnsetPropertyValues(this->Makefile, honorStandard, + warnCMP0067, warnCMP0067Variables); + objcState.LoadUnsetPropertyValues(this->Makefile, honorStandard, + warnCMP0067, warnCMP0067Variables); + objcxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard, + warnCMP0067, warnCMP0067Variables); - if (!this->WarnCMP0067.empty()) { + if (!warnCMP0067Variables.empty()) { std::ostringstream w; /* clang-format off */ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0067) << "\n" @@ -902,43 +861,17 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, "is not honoring language standard variables in the test project:\n" ; /* clang-format on */ - for (std::string const& vi : this->WarnCMP0067) { + for (std::string const& vi : warnCMP0067Variables) { w << " " << vi << "\n"; } this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str()); } - auto writeLanguageProperties = [&](bool testLang, - const std::string& langStandard, - const std::string& langStandardRequired, - const std::string& langExtensions, - const std::string& lang) { - if (testLang) { - if (!langStandard.empty()) { - writeProperty(fout, targetName, cmStrCat(lang, "_STANDARD"), - langStandard); - } - if (!langStandardRequired.empty()) { - writeProperty(fout, targetName, cmStrCat(lang, "_STANDARD_REQUIRED"), - langStandardRequired); - } - if (!langExtensions.empty()) { - writeProperty(fout, targetName, cmStrCat(lang, "_EXTENSIONS"), - langExtensions); - } - } - }; - - writeLanguageProperties(testC, cStandard, cStandardRequired, cExtensions, - "C"); - writeLanguageProperties(testObjC, objcStandard, objcStandardRequired, - objcExtensions, "OBJC"); - writeLanguageProperties(testCxx, cxxStandard, cxxStandardRequired, - cxxExtensions, "CXX"); - writeLanguageProperties(testObjCxx, objcxxStandard, objcxxStandardRequired, - objcxxExtensions, "OBJCXX"); - writeLanguageProperties(testCuda, cudaStandard, cudaStandardRequired, - cudaExtensions, "CUDA"); + cState.WriteProperties(fout, targetName); + cxxState.WriteProperties(fout, targetName); + cudaState.WriteProperties(fout, targetName); + objcState.WriteProperties(fout, targetName); + objcxxState.WriteProperties(fout, targetName); if (!linkOptions.empty()) { std::vector<std::string> options; @@ -1112,14 +1045,14 @@ void cmCoreTryCompile::FindOutputFile(const std::string& targetName, const char* config = this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION"); // if a config was specified try that first - if (config && config[0]) { + if (cmNonempty(config)) { std::string tmp = cmStrCat('/', config); searchDirs.push_back(std::move(tmp)); } searchDirs.emplace_back("/Debug"); #if defined(__APPLE__) std::string app = "/" + targetName + ".app"; - if (config && config[0]) { + if (cmNonempty(config)) { std::string tmp = cmStrCat('/', config, app); searchDirs.push_back(std::move(tmp)); } diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h index ae714a6..916572a 100644 --- a/Source/cmCoreTryCompile.h +++ b/Source/cmCoreTryCompile.h @@ -47,10 +47,6 @@ protected: std::string OutputFile; std::string FindErrorMessage; bool SrcFileSignature = false; - -private: - std::vector<std::string> WarnCMP0067; - std::string LookupStdVar(std::string const& var, bool warnCMP0067); }; #endif diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx index 9d492ba..9c4deea 100644 --- a/Source/cmCreateTestSourceList.cxx +++ b/Source/cmCreateTestSourceList.cxx @@ -127,7 +127,7 @@ bool cmCreateTestSourceList(std::vector<std::string> const& args, mf.AddDefinition("CMAKE_FORWARD_DECLARE_TESTS", forwardDeclareCode); mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTIRES", functionMapCode); bool res = true; - if (!mf.ConfigureFile(configFile, driver, false, true, false)) { + if (!mf.ConfigureFile(configFile, driver, false, true, false, true)) { res = false; } diff --git a/Source/cmDefinitions.cxx b/Source/cmDefinitions.cxx index 69a6427..4a4f87d 100644 --- a/Source/cmDefinitions.cxx +++ b/Source/cmDefinitions.cxx @@ -19,7 +19,6 @@ cmDefinitions::Def const& cmDefinitions::GetInternal(const std::string& key, { auto it = begin->Map.find(cm::String::borrow(key)); if (it != begin->Map.end()) { - it->second.Used = true; return it->second; } } @@ -108,16 +107,3 @@ void cmDefinitions::Unset(const std::string& key) { this->Map[key] = Def(); } - -std::vector<std::string> cmDefinitions::UnusedKeys() const -{ - std::vector<std::string> keys; - keys.reserve(this->Map.size()); - // Consider local definitions. - for (auto const& mi : this->Map) { - if (!mi.second.Used) { - keys.push_back(*mi.first.str_if_stable()); - } - } - return keys; -} diff --git a/Source/cmDefinitions.h b/Source/cmDefinitions.h index 0e38fb1..d57750a 100644 --- a/Source/cmDefinitions.h +++ b/Source/cmDefinitions.h @@ -48,9 +48,6 @@ public: /** Unset a definition. */ void Unset(const std::string& key); - /** List of unused keys. */ - std::vector<std::string> UnusedKeys() const; - private: /** String with existence boolean. */ struct Def @@ -62,7 +59,6 @@ private: { } cm::String Value; - bool Used = false; }; static Def NoDef; diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index 8f02d95..54418df 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -395,7 +395,7 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj, << ' ' << stampFileForShell; cmMakefile* mf = this->LocalGenerator->GetMakefile(); const char* cid = mf->GetDefinition("CMAKE_Fortran_COMPILER_ID"); - if (cid && *cid) { + if (cmNonempty(cid)) { makeDepends << ' ' << cid; } makeDepends << '\n'; diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 9f8a821..352eaf2 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -223,11 +223,9 @@ bool cmExportCommand(std::vector<std::string> const& args, ebfg->SetExportOld(arguments.ExportOld); // Compute the set of configurations exported. - std::vector<std::string> configurationTypes; - mf.GetConfigurations(configurationTypes); - if (configurationTypes.empty()) { - configurationTypes.emplace_back(); - } + std::vector<std::string> configurationTypes = + mf.GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + for (std::string const& ct : configurationTypes) { ebfg->AddConfiguration(ct); } diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 4d0e099..58aa391 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -567,8 +567,9 @@ void cmExportFileGenerator::PopulateCompatibleInterfaceProperties( if (gtarget->GetType() != cmStateEnums::INTERFACE_LIBRARY) { getCompatibleInterfaceProperties(gtarget, ifaceProperties, ""); - std::vector<std::string> configNames; - gtarget->Target->GetMakefile()->GetConfigurations(configNames); + std::vector<std::string> configNames = + gtarget->Target->GetMakefile()->GetGeneratorConfigs( + cmMakefile::ExcludeEmptyConfig); for (std::string const& cn : configNames) { getCompatibleInterfaceProperties(gtarget, ifaceProperties, cn); diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index 32b0ca9..511168b 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -95,7 +95,7 @@ struct Tree std::string path; // only one component of the path std::vector<Tree> folders; std::set<std::string> files; - void InsertPath(const std::vector<std::string>& splitted, + void InsertPath(const std::vector<std::string>& split, std::vector<std::string>::size_type start, const std::string& fileName); void BuildVirtualFolder(cmXMLWriter& xml) const; @@ -106,34 +106,34 @@ struct Tree const std::string& fsPath) const; }; -void Tree::InsertPath(const std::vector<std::string>& splitted, +void Tree::InsertPath(const std::vector<std::string>& split, std::vector<std::string>::size_type start, const std::string& fileName) { - if (start == splitted.size()) { + if (start == split.size()) { files.insert(fileName); return; } for (Tree& folder : folders) { - if (folder.path == splitted[start]) { - if (start + 1 < splitted.size()) { - folder.InsertPath(splitted, start + 1, fileName); + if (folder.path == split[start]) { + if (start + 1 < split.size()) { + folder.InsertPath(split, start + 1, fileName); return; } - // last part of splitted + // last part of split folder.files.insert(fileName); return; } } // Not found in folders, thus insert Tree newFolder; - newFolder.path = splitted[start]; - if (start + 1 < splitted.size()) { - newFolder.InsertPath(splitted, start + 1, fileName); + newFolder.path = split[start]; + if (start + 1 < split.size()) { + newFolder.InsertPath(split, start + 1, fileName); folders.push_back(newFolder); return; } - // last part of splitted + // last part of split newFolder.files.insert(fileName); folders.push_back(newFolder); } @@ -224,11 +224,11 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( const std::string& relative = cmSystemTools::RelativePath( it.second[0]->GetSourceDirectory(), listFile); - std::vector<std::string> splitted; - cmSystemTools::SplitPath(relative, splitted, false); + std::vector<std::string> split; + cmSystemTools::SplitPath(relative, split, false); // Split filename from path - std::string fileName = *(splitted.end() - 1); - splitted.erase(splitted.end() - 1, splitted.end()); + std::string fileName = *(split.end() - 1); + split.erase(split.end() - 1, split.end()); // We don't want paths with CMakeFiles in them // or do we? @@ -236,13 +236,12 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( // // Also we can disable external (outside the project) files by setting ON // CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable. - const bool excludeExternal = - cmIsOn(it.second[0]->GetMakefile()->GetSafeDefinition( - "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES")); - if (!splitted.empty() && + const bool excludeExternal = it.second[0]->GetMakefile()->IsOn( + "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES"); + if (!split.empty() && (!excludeExternal || (relative.find("..") == std::string::npos)) && relative.find("CMakeFiles") == std::string::npos) { - tree.InsertPath(splitted, 1, fileName); + tree.InsertPath(split, 1, fileName); } } } @@ -370,7 +369,7 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( std::string lang = s->GetOrDetermineLanguage(); if (lang == "C" || lang == "CXX" || lang == "CUDA") { std::string const& srcext = s->GetExtension(); - isCFile = cm->IsSourceExtension(srcext); + isCFile = cm->IsACLikeSourceExtension(srcext); } std::string const& fullPath = s->ResolveFullPath(); @@ -380,9 +379,8 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( cmSystemTools::RelativePath(lg->GetSourceDirectory(), fullPath); // Do not add this file if it has ".." in relative path and // if CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable is on. - const bool excludeExternal = - cmIsOn(lg->GetMakefile()->GetSafeDefinition( - "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES")); + const bool excludeExternal = lg->GetMakefile()->IsOn( + "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES"); if (excludeExternal && (relative.find("..") != std::string::npos)) { continue; diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index bf7555d..95cfb0a 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -227,8 +227,7 @@ std::string cmExtraCodeLiteGenerator::CollectSourceFiles( cmSystemTools::LowerCase(s->GetExtension()); // check whether it is a source or a include file // then put it accordingly into one of the two containers - if (cm->IsSourceExtension(extLower) || cm->IsCudaExtension(extLower) || - cm->IsFortranExtension(extLower)) { + if (cm->IsAKnownSourceExtension(extLower)) { cFiles[fullPath] = s; } else { otherFiles.insert(fullPath); diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 7bc4536..b6c0a7a 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -604,7 +604,7 @@ void cmExtraEclipseCDT4Generator::AppendIncludeDirectories( void cmExtraEclipseCDT4Generator::CreateCProjectFile() const { - std::set<std::string> emmited; + std::set<std::string> emitted; const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0]; const cmMakefile* mf = lg->GetMakefile(); @@ -751,7 +751,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const xml.EndElement(); // add pre-processor definitions to allow eclipse to gray out sections - emmited.clear(); + emitted.clear(); for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) { if (cmProp cdefs = @@ -780,8 +780,8 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const } // insert the definition if not already added. - if (emmited.find(def) == emmited.end()) { - emmited.insert(def); + if (emitted.find(def) == emitted.end()) { + emitted.insert(def); xml.StartElement("pathentry"); xml.Attribute("kind", "mac"); xml.Attribute("name", def); @@ -812,8 +812,8 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const } // insert the definition if not already added. - if (emmited.find(def) == emmited.end()) { - emmited.insert(def); + if (emitted.find(def) == emitted.end()) { + emitted.insert(def); xml.StartElement("pathentry"); xml.Attribute("kind", "mac"); xml.Attribute("name", def); @@ -844,8 +844,8 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const } // insert the definition if not already added. - if (emmited.find(def) == emmited.end()) { - emmited.insert(def); + if (emitted.find(def) == emitted.end()) { + emitted.insert(def); xml.StartElement("pathentry"); xml.Attribute("kind", "mac"); xml.Attribute("name", def); @@ -858,7 +858,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const } // include dirs - emmited.clear(); + emitted.clear(); for (const auto& lgen : this->GlobalGenerator->GetLocalGenerators()) { const auto& targets = lgen->GetGeneratorTargets(); for (const auto& target : targets) { @@ -868,7 +868,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const std::vector<std::string> includeDirs; std::string config = mf->GetSafeDefinition("CMAKE_BUILD_TYPE"); lgen->GetIncludeDirectories(includeDirs, target.get(), "C", config); - this->AppendIncludeDirectories(xml, includeDirs, emmited); + this->AppendIncludeDirectories(xml, includeDirs, emitted); } } // now also the system include directories, in case we found them in @@ -879,14 +879,14 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const std::string systemIncludeDirs = mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS"); std::vector<std::string> dirs = cmExpandedList(systemIncludeDirs); - this->AppendIncludeDirectories(xml, dirs, emmited); + this->AppendIncludeDirectories(xml, dirs, emitted); } compiler = mf->GetSafeDefinition("CMAKE_CXX_COMPILER"); if (this->CXXEnabled && !compiler.empty()) { std::string systemIncludeDirs = mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS"); std::vector<std::string> dirs = cmExpandedList(systemIncludeDirs); - this->AppendIncludeDirectories(xml, dirs, emmited); + this->AppendIncludeDirectories(xml, dirs, emitted); } xml.EndElement(); // storageModule @@ -895,7 +895,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const xml.StartElement("storageModule"); xml.Attribute("moduleId", "org.eclipse.cdt.make.core.buildtargets"); xml.StartElement("buildTargets"); - emmited.clear(); + emitted.clear(); const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM"); const std::string& makeArgs = mf->GetSafeDefinition("CMAKE_ECLIPSE_MAKE_ARGUMENTS"); diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 613a943..3e265a0 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -349,6 +349,13 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject( if (language.empty()) { language = "C"; } + + // explicitly add the explicit language flag before any other flag + // this way backwards compatibility with user flags is maintained + if (source->GetProperty("LANGUAGE")) { + lg->AppendFeatureOptions(flags, language, "EXPLICIT_LANGUAGE"); + } + std::string const& config = lg->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"); diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx index 594969b..c2ab2f1 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 = 1; +static unsigned int const CodeModelV2Minor = 2; void cmFileAPI::BuildClientRequestCodeModel( ClientRequest& r, std::vector<RequestVersion> const& versions) diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index fe331ec..55fb115 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -175,6 +175,38 @@ public: } }; +template <typename T> +class JBTs +{ +public: + JBTs(T v = T(), std::vector<JBTIndex> ids = std::vector<JBTIndex>()) + : Value(std::move(v)) + , Backtraces(std::move(ids)) + { + } + T Value; + std::vector<JBTIndex> Backtraces; + friend bool operator==(JBTs<T> const& l, JBTs<T> const& r) + { + if ((l.Value == r.Value) && (l.Backtraces.size() == r.Backtraces.size())) { + for (size_t i = 0; i < l.Backtraces.size(); i++) { + if (l.Backtraces[i].Index != r.Backtraces[i].Index) { + return false; + } + } + } + return true; + } + static bool ValueEq(JBTs<T> const& l, JBTs<T> const& r) + { + return l.Value == r.Value; + } + static bool ValueLess(JBTs<T> const& l, JBTs<T> const& r) + { + return l.Value < r.Value; + } +}; + class BacktraceData { std::string TopSource; @@ -277,6 +309,7 @@ struct CompileData std::string Language; std::string Sysroot; + JBTs<std::string> LanguageStandard; std::vector<JBT<std::string>> Flags; std::vector<JBT<std::string>> Defines; std::vector<JBT<std::string>> PrecompileHeaders; @@ -287,6 +320,7 @@ struct CompileData return (l.Language == r.Language && l.Sysroot == r.Sysroot && l.Flags == r.Flags && l.Defines == r.Defines && l.PrecompileHeaders == r.PrecompileHeaders && + l.LanguageStandard == r.LanguageStandard && l.Includes == r.Includes); } }; @@ -320,6 +354,12 @@ struct hash<CompileData> result = result ^ hash<std::string>()(i.Value) ^ hash<Json::ArrayIndex>()(i.Backtrace.Index); } + if (!in.LanguageStandard.Value.empty()) { + result = result ^ hash<std::string>()(in.LanguageStandard.Value); + for (JBTIndex backtrace : in.LanguageStandard.Backtraces) { + result = result ^ hash<Json::ArrayIndex>()(backtrace.Index); + } + } return result; } }; @@ -363,6 +403,16 @@ class Target return JBT<T>(bt.Value, this->Backtraces.Add(bt.Backtrace)); } + template <typename T> + JBTs<T> ToJBTs(BTs<T> const& bts) + { + std::vector<JBTIndex> ids; + for (cmListFileBacktrace const& backtrace : bts.Backtraces) { + ids.emplace_back(this->Backtraces.Add(backtrace)); + } + return JBTs<T>(bts.Value, ids); + } + void ProcessLanguages(); void ProcessLanguage(std::string const& lang); @@ -377,6 +427,7 @@ class Target Json::Value DumpCompileData(CompileData const& cd); Json::Value DumpInclude(CompileData::IncludeEntry const& inc); Json::Value DumpPrecompileHeader(JBT<std::string> const& header); + Json::Value DumpLanguageStandard(JBTs<std::string> const& standard); Json::Value DumpDefine(JBT<std::string> const& def); Json::Value DumpSources(); Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk, @@ -438,7 +489,7 @@ Json::Value Codemodel::DumpConfigurations() const auto& makefiles = gg->GetMakefiles(); if (!makefiles.empty()) { std::vector<std::string> const& configs = - makefiles[0]->GetGeneratorConfigs(); + makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); for (std::string const& config : configs) { configurations.append(this->DumpConfiguration(config)); } @@ -574,7 +625,7 @@ Json::Value CodemodelConfig::DumpTargets() for (cmGeneratorTarget* gt : targetList) { if (gt->GetType() == cmStateEnums::GLOBAL_TARGET || - gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + !gt->IsInBuildSystem()) { continue; } @@ -838,6 +889,11 @@ void Target::ProcessLanguage(std::string const& lang) for (BT<std::string> const& pch : precompileHeaders) { cd.PrecompileHeaders.emplace_back(this->ToJBT(pch)); } + BTs<std::string> const* languageStandard = + this->GT->GetLanguageStandardProperty(lang, this->Config); + if (languageStandard) { + cd.LanguageStandard = this->ToJBTs(*languageStandard); + } } Json::ArrayIndex Target::AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si) @@ -996,6 +1052,9 @@ CompileData Target::MergeCompileData(CompileData const& fd) // All compile groups share the precompile headers of the target. cd.PrecompileHeaders = td.PrecompileHeaders; + // All compile groups share the language standard of the target. + cd.LanguageStandard = td.LanguageStandard; + // 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()); @@ -1153,6 +1212,10 @@ Json::Value Target::DumpCompileData(CompileData const& cd) } result["precompileHeaders"] = std::move(precompileHeaders); } + if (!cd.LanguageStandard.Value.empty()) { + result["languageStandard"] = + this->DumpLanguageStandard(cd.LanguageStandard); + } return result; } @@ -1176,6 +1239,20 @@ Json::Value Target::DumpPrecompileHeader(JBT<std::string> const& header) return precompileHeader; } +Json::Value Target::DumpLanguageStandard(JBTs<std::string> const& standard) +{ + Json::Value languageStandard = Json::objectValue; + languageStandard["standard"] = standard.Value; + if (!standard.Backtraces.empty()) { + Json::Value backtraces = Json::arrayValue; + for (JBTIndex backtrace : standard.Backtraces) { + backtraces.append(backtrace.Index); + } + languageStandard["backtraces"] = backtraces; + } + return languageStandard; +} + Json::Value Target::DumpDefine(JBT<std::string> const& def) { Json::Value define = Json::objectValue; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 7101e22..8d20d35 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -1394,8 +1394,10 @@ size_t cmWriteToFileCallback(void* ptr, size_t size, size_t nmemb, void* data) { int realsize = static_cast<int>(size * nmemb); cmsys::ofstream* fout = static_cast<cmsys::ofstream*>(data); - const char* chPtr = static_cast<char*>(ptr); - fout->write(chPtr, realsize); + if (fout) { + const char* chPtr = static_cast<char*>(ptr); + fout->write(chPtr, realsize); + } return realsize; } @@ -1551,15 +1553,14 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, { #if !defined(CMAKE_BOOTSTRAP) auto i = args.begin(); - if (args.size() < 3) { - status.SetError("DOWNLOAD must be called with at least three arguments."); + if (args.size() < 2) { + status.SetError("DOWNLOAD must be called with at least two arguments."); return false; } ++i; // Get rid of subcommand std::string url = *i; ++i; - std::string file = *i; - ++i; + std::string file; long timeout = 0; long inactivity_timeout = 0; @@ -1690,6 +1691,8 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, return false; } curl_headers.push_back(*i); + } else if (file.empty()) { + file = *i; } else { // Do not return error for compatibility reason. std::string err = cmStrCat("Unexpected argument: ", *i); @@ -1697,11 +1700,18 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, } ++i; } + // Can't calculate hash if we don't save the file. + // TODO Incrementally calculate hash in the write callback as the file is + // being downloaded so this check can be relaxed. + if (file.empty() && hash) { + status.SetError("DOWNLOAD cannot calculate hash if file is not saved."); + return false; + } // If file exists already, and caller specified an expected md5 or sha, // and the existing file already has the expected hash, then simply // return. // - if (cmSystemTools::FileExists(file) && hash.get()) { + if (!file.empty() && cmSystemTools::FileExists(file) && hash.get()) { std::string msg; std::string actualHash = hash->HashFile(file); if (actualHash == expectedHash) { @@ -1716,20 +1726,26 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, // Make sure parent directory exists so we can write to the file // as we receive downloaded bits from curl... // - std::string dir = cmSystemTools::GetFilenamePath(file); - if (!dir.empty() && !cmSystemTools::FileExists(dir) && - !cmSystemTools::MakeDirectory(dir)) { - std::string errstring = "DOWNLOAD error: cannot create directory '" + dir + - "' - Specify file by full path name and verify that you " - "have directory creation and file write privileges."; - status.SetError(errstring); - return false; + if (!file.empty()) { + std::string dir = cmSystemTools::GetFilenamePath(file); + if (!dir.empty() && !cmSystemTools::FileExists(dir) && + !cmSystemTools::MakeDirectory(dir)) { + std::string errstring = "DOWNLOAD error: cannot create directory '" + + dir + + "' - Specify file by full path name and verify that you " + "have directory creation and file write privileges."; + status.SetError(errstring); + return false; + } } - cmsys::ofstream fout(file.c_str(), std::ios::binary); - if (!fout) { - status.SetError("DOWNLOAD cannot open file for write."); - return false; + cmsys::ofstream fout; + if (!file.empty()) { + fout.open(file.c_str(), std::ios::binary); + if (!fout) { + status.SetError("DOWNLOAD cannot open file for write."); + return false; + } } # if defined(_WIN32) @@ -1791,7 +1807,8 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, cmFileCommandVectorOfChar chunkDebug; - res = ::curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fout); + res = ::curl_easy_setopt(curl, CURLOPT_WRITEDATA, + file.empty() ? nullptr : &fout); check_curl_result(res, "DOWNLOAD cannot set write data: "); res = ::curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &chunkDebug); @@ -1865,8 +1882,10 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, // Explicitly flush/close so we can measure the md5 accurately. // - fout.flush(); - fout.close(); + if (!file.empty()) { + fout.flush(); + fout.close(); + } // Verify MD5 sum if requested: // @@ -2918,7 +2937,7 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, } fout.SetCopyIfDifferent(true); - // copy intput to output and expand variables from input at the same time + // copy input to output and expand variables from input at the same time std::stringstream sin(input, std::ios::in); std::string inLine; std::string outLine; diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx index 627e05b..5d44a06 100644 --- a/Source/cmFileCopier.cxx +++ b/Source/cmFileCopier.cxx @@ -173,7 +173,7 @@ bool cmFileCopier::GetDefaultDirectoryPermissions(mode_t** mode) // check if default dir creation permissions were set const char* default_dir_install_permissions = this->Makefile->GetDefinition( "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS"); - if (default_dir_install_permissions && *default_dir_install_permissions) { + if (cmNonempty(default_dir_install_permissions)) { std::vector<std::string> items = cmExpandedList(default_dir_install_permissions); for (const auto& arg : items) { diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index 3e97150..3401eff 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -208,10 +208,10 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths) const char* sysrootLink = this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK"); const char* rootPath = this->Makefile->GetDefinition("CMAKE_FIND_ROOT_PATH"); - const bool noSysroot = !sysroot || !*sysroot; - const bool noCompileSysroot = !sysrootCompile || !*sysrootCompile; - const bool noLinkSysroot = !sysrootLink || !*sysrootLink; - const bool noRootPath = !rootPath || !*rootPath; + const bool noSysroot = !cmNonempty(sysroot); + const bool noCompileSysroot = !cmNonempty(sysrootCompile); + const bool noLinkSysroot = !cmNonempty(sysrootLink); + const bool noRootPath = !cmNonempty(rootPath); if (noSysroot && noCompileSysroot && noLinkSysroot && noRootPath) { return; } diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 8d5b177..ae06047 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -1121,7 +1121,7 @@ void cmFindPackageCommand::AppendToFoundProperty(bool found) std::vector<std::string> foundContents; cmProp foundProp = this->Makefile->GetState()->GetGlobalProperty("PACKAGES_FOUND"); - if (foundProp && !foundProp->empty()) { + if (cmNonempty(foundProp)) { cmExpandList(*foundProp, foundContents, false); auto nameIt = std::find(foundContents.begin(), foundContents.end(), this->Name); @@ -1133,7 +1133,7 @@ void cmFindPackageCommand::AppendToFoundProperty(bool found) std::vector<std::string> notFoundContents; cmProp notFoundProp = this->Makefile->GetState()->GetGlobalProperty("PACKAGES_NOT_FOUND"); - if (notFoundProp && !notFoundProp->empty()) { + if (cmNonempty(notFoundProp)) { cmExpandList(*notFoundProp, notFoundContents, false); auto nameIt = std::find(notFoundContents.begin(), notFoundContents.end(), this->Name); @@ -1166,9 +1166,9 @@ void cmFindPackageCommand::AppendSuccessInformation() std::string found = cmStrCat(this->Name, "_FOUND"); std::string upperFound = cmSystemTools::UpperCase(found); - const char* upperResult = this->Makefile->GetDefinition(upperFound); - const char* result = this->Makefile->GetDefinition(found); - bool packageFound = ((cmIsOn(result)) || (cmIsOn(upperResult))); + bool upperResult = this->Makefile->IsOn(upperFound); + bool result = this->Makefile->IsOn(found); + bool packageFound = (result || upperResult); this->AppendToFoundProperty(packageFound); diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx index 4b88bea..77728ec 100644 --- a/Source/cmFindProgramCommand.cxx +++ b/Source/cmFindProgramCommand.cxx @@ -4,6 +4,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmPolicies.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -19,6 +20,7 @@ struct cmFindProgramHelper cmFindProgramHelper(cmMakefile* makefile, cmFindBase const* base) : DebugSearches("find_program", base) , Makefile(makefile) + , PolicyCMP0109(makefile->GetPolicyStatus(cmPolicies::CMP0109)) { #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) // Consider platform-specific extensions. @@ -48,6 +50,8 @@ struct cmFindProgramHelper cmFindBaseDebugState DebugSearches; cmMakefile* Makefile; + cmPolicies::PolicyStatus PolicyCMP0109; + void AddName(std::string const& name) { this->Names.push_back(name); } void SetName(std::string const& name) { @@ -85,7 +89,7 @@ struct cmFindProgramHelper this->TestNameExt = cmStrCat(name, ext); this->TestPath = cmSystemTools::CollapseFullPath(this->TestNameExt, path); - bool exists = cmSystemTools::FileExists(this->TestPath, true); + bool exists = this->FileIsExecutable(this->TestPath); exists ? this->DebugSearches.FoundAt(this->TestPath) : this->DebugSearches.FailedAt(this->TestPath); if (exists) { @@ -95,6 +99,48 @@ struct cmFindProgramHelper } return false; } + bool FileIsExecutable(std::string const& file) const + { + switch (this->PolicyCMP0109) { + case cmPolicies::OLD: + return cmSystemTools::FileExists(file, true); + case cmPolicies::NEW: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + return cmSystemTools::FileIsExecutable(file); + default: + break; + } + bool const isExeOld = cmSystemTools::FileExists(file, true); + bool const isExeNew = cmSystemTools::FileIsExecutable(file); + if (isExeNew == isExeOld) { + return isExeNew; + } + if (isExeNew) { + this->Makefile->IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0109), + "\n" + "The file\n" + " ", + file, + "\n" + "is executable but not readable. " + "CMake is ignoring it for compatibility.")); + } else { + this->Makefile->IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0109), + "\n" + "The file\n" + " ", + file, + "\n" + "is readable but not executable. " + "CMake is using it for compatibility.")); + } + return isExeOld; + } }; cmFindProgramCommand::cmFindProgramCommand(cmExecutionStatus& status) @@ -266,14 +312,13 @@ std::string cmFindProgramCommand::GetBundleExecutable( if (executableURL != nullptr) { const int MAX_OSX_PATH_SIZE = 1024; - char buffer[MAX_OSX_PATH_SIZE]; + UInt8 buffer[MAX_OSX_PATH_SIZE]; - // Convert the CFString to a C string - CFStringGetCString(CFURLGetString(executableURL), buffer, - MAX_OSX_PATH_SIZE, kCFStringEncodingUTF8); - - // And finally to a c++ string - executable = bundlePath + "/Contents/MacOS/" + std::string(buffer); + if (CFURLGetFileSystemRepresentation(executableURL, false, buffer, + MAX_OSX_PATH_SIZE)) { + executable = bundlePath + "/Contents/MacOS/" + + std::string(reinterpret_cast<char*>(buffer)); + } // Only release CFURLRef if it's not null CFRelease(executableURL); } diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx index 9cee0e6..2768547 100644 --- a/Source/cmGeneratedFileStream.cxx +++ b/Source/cmGeneratedFileStream.cxx @@ -14,10 +14,11 @@ #endif cmGeneratedFileStream::cmGeneratedFileStream(Encoding encoding) + : OriginalLocale(getloc()) { #ifndef CMAKE_BOOTSTRAP if (encoding != codecvt::None) { - imbue(std::locale(getloc(), new codecvt(encoding))); + imbue(std::locale(OriginalLocale, new codecvt(encoding))); } #else static_cast<void>(encoding); @@ -122,10 +123,17 @@ void cmGeneratedFileStreamBase::Open(std::string const& name) // Create the name of the temporary file. this->TempName = name; #if defined(__VMS) - this->TempName += "_tmp"; + this->TempName += "_"; #else - this->TempName += ".tmp"; + this->TempName += "."; #endif + if (!this->TempExt.empty()) { + this->TempName += this->TempExt; + } else { + char buf[64]; + sprintf(buf, "tmp%05x", cmSystemTools::RandomSeed() & 0xFFFFF); + this->TempName += buf; + } // Make sure the temporary file that will be used is not present. cmSystemTools::RemoveFile(this->TempName); @@ -216,3 +224,19 @@ void cmGeneratedFileStream::SetName(const std::string& fname) { this->Name = fname; } + +void cmGeneratedFileStream::SetTempExt(std::string const& ext) +{ + this->TempExt = ext; +} + +void cmGeneratedFileStream::WriteRaw(std::string const& data) +{ +#ifndef CMAKE_BOOTSTRAP + std::locale activeLocale = this->imbue(this->OriginalLocale); + this->write(data.data(), data.size()); + this->imbue(activeLocale); +#else + this->write(data.data(), data.size()); +#endif +} diff --git a/Source/cmGeneratedFileStream.h b/Source/cmGeneratedFileStream.h index a9088ac..f6da86e 100644 --- a/Source/cmGeneratedFileStream.h +++ b/Source/cmGeneratedFileStream.h @@ -43,6 +43,9 @@ protected: // The name of the final destination file for the output. std::string Name; + // The extension of the temporary file. + std::string TempExt; + // The name of the temporary file. std::string TempName; @@ -138,6 +141,22 @@ public: * the output file to be changed during the use of cmGeneratedFileStream. */ void SetName(const std::string& fname); + + /** + * Set set a custom temporary file extension used with 'Open'. + * This does not work if the file was opened by the constructor. + */ + void SetTempExt(std::string const& ext); + + /** + * Writes the given string directly to the file without changing the + * encoding. + */ + void WriteRaw(std::string const& data); + +private: + // The original locale of the stream (performs no encoding conversion). + std::locale OriginalLocale; }; #endif diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 6e293d5..840f511 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -406,9 +406,3 @@ const std::string& cmGeneratorExpressionInterpreter::Evaluate( this->LocalGenerator, this->Config, this->HeadTarget, &dagChecker, nullptr, this->Language); } - -const std::string& cmGeneratorExpressionInterpreter::Evaluate( - const char* expression, const std::string& property) -{ - return this->Evaluate(std::string(expression ? expression : ""), property); -} diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index 75bba02..09d8b88 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -199,8 +199,6 @@ public: const std::string& Evaluate(std::string expression, const std::string& property); - const std::string& Evaluate(const char* expression, - const std::string& property); protected: cmGeneratorExpression GeneratorExpression; diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index 4f379cd..e223f15 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -154,6 +154,14 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() const return this->Top()->Property == "INTERFACE_POSITION_INDEPENDENT_CODE"; } +bool cmGeneratorExpressionDAGChecker::EvaluatingCompileExpression() const +{ + cm::string_view property(this->Top()->Property); + + return property == "INCLUDE_DIRECTORIES"_s || + property == "COMPILE_DEFINITIONS"_s || property == "COMPILE_OPTIONS"_s; +} + bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const { cm::string_view property(this->Top()->Property); diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index c2c5b6b..ac2314c 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -68,6 +68,7 @@ struct cmGeneratorExpressionDAGChecker bool EvaluatingGenexExpression() const; bool EvaluatingPICExpression() const; + bool EvaluatingCompileExpression() const; bool EvaluatingLinkExpression() const; bool EvaluatingLinkOptionsExpression() const; diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx index 9e8707d..1107adb 100644 --- a/Source/cmGeneratorExpressionEvaluationFile.cxx +++ b/Source/cmGeneratorExpressionEvaluationFile.cxx @@ -157,12 +157,8 @@ void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg) std::map<std::string, std::string> outputFiles; - std::vector<std::string> allConfigs; - lg->GetMakefile()->GetConfigurations(allConfigs); - - if (allConfigs.empty()) { - allConfigs.emplace_back(); - } + std::vector<std::string> allConfigs = + lg->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); std::vector<std::string> enabledLanguages; cmGlobalGenerator* gg = lg->GetGlobalGenerator(); diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index e4fb67e..fdc8f29 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -37,6 +37,7 @@ #include "cmPolicies.h" #include "cmProperty.h" #include "cmRange.h" +#include "cmStandardLevelResolver.h" #include "cmState.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" @@ -881,7 +882,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode { ConfigurationTestNode() {} // NOLINT(modernize-use-equals-default) - int NumExpectedParameters() const override { return OneOrZeroParameters; } + int NumExpectedParameters() const override { return ZeroOrMoreParameters; } std::string Evaluate( const std::vector<std::string>& parameters, @@ -899,13 +900,15 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode return std::string(); } context->HadContextSensitiveCondition = true; - if (context->Config.empty()) { - return parameters.front().empty() ? "1" : "0"; - } - - if (cmsysString_strcasecmp(parameters.front().c_str(), - context->Config.c_str()) == 0) { - return "1"; + for (auto& param : parameters) { + if (context->Config.empty()) { + if (param.empty()) { + return "1"; + } + } else if (cmsysString_strcasecmp(param.c_str(), + context->Config.c_str()) == 0) { + return "1"; + } } if (context->CurrentTarget && context->CurrentTarget->IsImported()) { @@ -922,10 +925,12 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode "MAP_IMPORTED_CONFIG_", cmSystemTools::UpperCase(context->Config)); if (cmProp mapValue = context->CurrentTarget->GetProperty(mapProp)) { cmExpandList(cmSystemTools::UpperCase(*mapValue), mappedConfigs); - return cm::contains(mappedConfigs, - cmSystemTools::UpperCase(parameters.front())) - ? "1" - : "0"; + + for (auto& param : parameters) { + if (cm::contains(mappedConfigs, cmSystemTools::UpperCase(param))) { + return "1"; + } + } } } } @@ -962,9 +967,10 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode const std::vector<std::string>& parameters, cmGeneratorExpressionContext* context, const GeneratorExpressionContent* content, - cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + cmGeneratorExpressionDAGChecker* dagChecker) const override { - if (context->Language.empty()) { + if (context->Language.empty() && + (!dagChecker || !dagChecker->EvaluatingCompileExpression())) { reportError( context, content->GetOriginalExpression(), "$<COMPILE_LANGUAGE:...> may only be used to specify include " @@ -1009,7 +1015,9 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode const GeneratorExpressionContent* content, cmGeneratorExpressionDAGChecker* dagChecker) const override { - if (!context->HeadTarget || context->Language.empty()) { + if (!context->HeadTarget || + (context->Language.empty() && + (!dagChecker || !dagChecker->EvaluatingCompileExpression()))) { // reportError(context, content->GetOriginalExpression(), ""); reportError( context, content->GetOriginalExpression(), @@ -1468,8 +1476,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } if (isInterfaceProperty) { - return target->EvaluateInterfaceProperty(propertyName, context, - dagCheckerParent); + return cmGeneratorExpression::StripEmptyListElements( + target->EvaluateInterfaceProperty(propertyName, context, + dagCheckerParent)); } cmGeneratorExpressionDAGChecker dagChecker( @@ -1555,8 +1564,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } if (!interfacePropertyName.empty()) { - result = this->EvaluateDependentExpression(result, context->LG, context, - target, &dagChecker, target); + result = cmGeneratorExpression::StripEmptyListElements( + this->EvaluateDependentExpression(result, context->LG, context, target, + &dagChecker, target)); std::string linkedTargetsContent = getLinkedTargetsContent( target, interfacePropertyName, context, &dagChecker); if (!linkedTargetsContent.empty()) { @@ -1703,12 +1713,12 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode static LangMap availableFeatures; LangMap testedFeatures; - + cmStandardLevelResolver standardResolver(context->LG->GetMakefile()); for (std::string const& p : parameters) { std::string error; std::string lang; - if (!context->LG->GetMakefile()->CompileFeatureKnown( - context->HeadTarget->Target, p, lang, &error)) { + if (!standardResolver.CompileFeatureKnown( + context->HeadTarget->Target->GetName(), p, lang, &error)) { reportError(context, content->GetOriginalExpression(), error); return std::string(); } @@ -1716,7 +1726,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode if (availableFeatures.find(lang) == availableFeatures.end()) { const char* featuresKnown = - context->LG->GetMakefile()->CompileFeaturesAvailable(lang, &error); + standardResolver.CompileFeaturesAvailable(lang, &error); if (!featuresKnown) { reportError(context, content->GetOriginalExpression(), error); return std::string(); @@ -1741,10 +1751,10 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode // All features known for the language are always available. continue; } - if (!context->LG->GetMakefile()->HaveStandardAvailable( - target->Target, lit.first, it)) { + if (!standardResolver.HaveStandardAvailable(target, lit.first, + context->Config, it)) { if (evalLL) { - cmProp l = target->GetProperty(lit.first + "_STANDARD"); + cmProp l = target->GetLanguageStandard(lit.first, context->Config); if (!l) { l = standardDefault; } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index ab6a26c..9611e14 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -43,6 +43,7 @@ #include "cmSourceFile.h" #include "cmSourceFileLocation.h" #include "cmSourceFileLocationKind.h" +#include "cmStandardLevelResolver.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -364,7 +365,7 @@ std::string cmGeneratorTarget::GetExportName() const { cmProp exportName = this->GetProperty("EXPORT_NAME"); - if (exportName && !exportName->empty()) { + if (cmNonempty(exportName)) { if (!cmGeneratorExpression::IsValidTargetName(*exportName)) { std::ostringstream e; e << "EXPORT_NAME property \"" << *exportName << "\" for \"" @@ -379,11 +380,6 @@ std::string cmGeneratorTarget::GetExportName() const cmProp cmGeneratorTarget::GetProperty(const std::string& prop) const { - if (!cmTargetPropertyComputer::PassesWhitelist( - this->GetType(), prop, this->Makefile->GetMessenger(), - this->GetBacktrace())) { - return nullptr; - } if (cmProp result = cmTargetPropertyComputer::GetProperty( this, prop, this->Makefile->GetMessenger(), this->GetBacktrace())) { return result; @@ -801,7 +797,8 @@ void cmGeneratorTarget::GetObjectSources( void cmGeneratorTarget::ComputeObjectMapping() { - auto const& configs = this->Makefile->GetGeneratorConfigs(); + auto const& configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); std::set<std::string> configSet(configs.begin(), configs.end()); if (configSet == this->VisitedConfigsForObjects) { return; @@ -813,18 +810,18 @@ void cmGeneratorTarget::ComputeObjectMapping() } } -const char* cmGeneratorTarget::GetFeature(const std::string& feature, - const std::string& config) const +cmProp cmGeneratorTarget::GetFeature(const std::string& feature, + const std::string& config) const { if (!config.empty()) { std::string featureConfig = cmStrCat(feature, '_', cmSystemTools::UpperCase(config)); if (cmProp value = this->GetProperty(featureConfig)) { - return value->c_str(); + return value; } } if (cmProp value = this->GetProperty(feature)) { - return value->c_str(); + return value; } return this->LocalGenerator->GetFeature(feature, config); } @@ -851,10 +848,9 @@ const char* cmGeneratorTarget::GetLinkPIEProperty( bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang, std::string const& config) const { - const char* feature = "INTERPROCEDURAL_OPTIMIZATION"; - const bool result = cmIsOn(this->GetFeature(feature, config)); + cmProp feature = this->GetFeature("INTERPROCEDURAL_OPTIMIZATION", config); - if (!result) { + if (!cmIsOn(feature)) { // 'INTERPROCEDURAL_OPTIMIZATION' is off, no need to check policies return false; } @@ -947,6 +943,61 @@ bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const return it != this->ExplicitObjectName.end(); } +BTs<std::string> const* cmGeneratorTarget::GetLanguageStandardProperty( + std::string const& lang, std::string const& config) const +{ + std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang); + auto langStandardIter = this->LanguageStandardMap.find(key); + if (langStandardIter != this->LanguageStandardMap.end()) { + return &langStandardIter->second; + } + + return this->Target->GetLanguageStandardProperty( + cmStrCat(lang, "_STANDARD")); +} + +cmProp cmGeneratorTarget::GetLanguageStandard(std::string const& lang, + std::string const& config) const +{ + BTs<std::string> const* languageStandard = + this->GetLanguageStandardProperty(lang, config); + + if (languageStandard) { + return &(languageStandard->Value); + } + + return nullptr; +} + +cmProp cmGeneratorTarget::GetPropertyWithPairedLanguageSupport( + std::string const& lang, const char* suffix) const +{ + cmProp propertyValue = this->Target->GetProperty(cmStrCat(lang, suffix)); + if (propertyValue == nullptr) { + // Check if we should use the value set by another language. + if (lang == "OBJC") { + propertyValue = this->GetPropertyWithPairedLanguageSupport("C", suffix); + } else if (lang == "OBJCXX" || lang == "CUDA") { + propertyValue = + this->GetPropertyWithPairedLanguageSupport("CXX", suffix); + } + } + return propertyValue; +} + +cmProp cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const +{ + return this->GetPropertyWithPairedLanguageSupport(lang, "_EXTENSIONS"); +} + +bool cmGeneratorTarget::GetLanguageStandardRequired( + std::string const& lang) const +{ + cmProp p = + this->GetPropertyWithPairedLanguageSupport(lang, "_STANDARD_REQUIRED"); + return cmIsOn(p); +} + void cmGeneratorTarget::GetModuleDefinitionSources( std::vector<cmSourceFile const*>& data, const std::string& config) const { @@ -1033,6 +1084,62 @@ std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPostBuildCommands() return this->Target->GetPostBuildCommands(); } +void cmGeneratorTarget::AppendCustomCommandSideEffects( + std::set<cmGeneratorTarget const*>& sideEffects) const +{ + if (!this->GetPreBuildCommands().empty() || + !this->GetPreLinkCommands().empty() || + !this->GetPostBuildCommands().empty()) { + sideEffects.insert(this); + } else { + for (auto const& source : this->GetAllConfigSources()) { + if (source.Source->GetCustomCommand() != nullptr) { + sideEffects.insert(this); + break; + } + } + } +} + +void cmGeneratorTarget::AppendLanguageSideEffects( + std::map<std::string, std::set<cmGeneratorTarget const*>>& sideEffects) const +{ + static const std::set<cm::string_view> LANGS_WITH_NO_SIDE_EFFECTS = { + "C"_s, "CXX"_s, "OBJC"_s, "OBJCXX"_s, "ASM"_s, "CUDA"_s, + }; + + for (auto const& lang : this->GetAllConfigCompileLanguages()) { + if (!LANGS_WITH_NO_SIDE_EFFECTS.count(lang)) { + sideEffects[lang].insert(this); + } + } +} + +bool cmGeneratorTarget::IsInBuildSystem() const +{ + if (this->IsImported()) { + return false; + } + switch (this->Target->GetType()) { + case cmStateEnums::EXECUTABLE: + case cmStateEnums::STATIC_LIBRARY: + case cmStateEnums::SHARED_LIBRARY: + case cmStateEnums::MODULE_LIBRARY: + case cmStateEnums::OBJECT_LIBRARY: + case cmStateEnums::UTILITY: + case cmStateEnums::GLOBAL_TARGET: + return true; + case cmStateEnums::INTERFACE_LIBRARY: + // An INTERFACE library is in the build system if it has SOURCES. + if (!this->SourceEntries.empty()) { + return true; + } + case cmStateEnums::UNKNOWN_LIBRARY: + break; + } + return false; +} + bool cmGeneratorTarget::IsImported() const { return this->Target->IsImported(); @@ -1043,6 +1150,11 @@ bool cmGeneratorTarget::IsImportedGloballyVisible() const return this->Target->IsImportedGloballyVisible(); } +bool cmGeneratorTarget::CanCompileSources() const +{ + return this->Target->CanCompileSources(); +} + const std::string& cmGeneratorTarget::GetLocationForBuild() const { static std::string location; @@ -1137,7 +1249,7 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( // If this target itself has a non-empty property value, we are done. cmProp p = this->GetProperty(prop); - maybeInterfaceProp = p && !p->empty(); + maybeInterfaceProp = cmNonempty(p); // Otherwise, recurse to interface dependencies. if (!maybeInterfaceProp) { @@ -1309,7 +1421,7 @@ void AddSwiftImplicitIncludeDirectories( for (const cmLinkImplItem& library : libraries->Libraries) { if (const cmGeneratorTarget* dependency = library.Target) { - if (dependency->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!dependency->IsInBuildSystem()) { continue; } if (cm::contains(dependency->GetAllConfigCompileLanguages(), @@ -1466,7 +1578,6 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( std::string const& config) const { std::vector<BT<std::string>> files; - assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY); if (!this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) { // At configure-time, this method can be called as part of getting the @@ -1658,9 +1769,11 @@ 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) { + } else if (this->Target->GetType() == cmStateEnums::UTILITY || + this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY + // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 + // NOLINTNEXTLINE(bugprone-branch-clone) + ) { kind = SourceKindExtra; } else if (this->IsSourceFilePartOfUnityBatch(sf->ResolveFullPath())) { kind = SourceKindUnityBatched; @@ -1726,8 +1839,8 @@ cmGeneratorTarget::GetAllConfigSources() const void cmGeneratorTarget::ComputeAllConfigSources() const { - std::vector<std::string> configs; - this->Makefile->GetConfigurations(configs); + std::vector<std::string> configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); std::map<cmSourceFile const*, size_t> index; @@ -1787,12 +1900,12 @@ std::string cmGeneratorTarget::GetCompilePDBName( std::string configUpper = cmSystemTools::UpperCase(config); std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper); cmProp config_name = this->GetProperty(configProp); - if (config_name && !config_name->empty()) { + if (cmNonempty(config_name)) { return prefix + *config_name + ".pdb"; } cmProp name = this->GetProperty("COMPILE_PDB_NAME"); - if (name && !name->empty()) { + if (cmNonempty(name)) { return prefix + *name + ".pdb"; } @@ -1939,7 +2052,7 @@ bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const std::string sepVar = cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG_SEP"); const char* sep = this->Makefile->GetDefinition(sepVar); - if (sep && *sep) { + if (cmNonempty(sep)) { // TODO: Add ELF check to ABI detection and get rid of // CMAKE_EXECUTABLE_FORMAT. if (const char* fmt = @@ -2239,7 +2352,7 @@ std::string cmGeneratorTarget::GetInstallNameDirForInstallTree( cmProp install_name_dir = this->GetProperty("INSTALL_NAME_DIR"); if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) { - if (install_name_dir && !install_name_dir->empty()) { + if (cmNonempty(install_name_dir)) { dir = *install_name_dir; cmGeneratorExpression::ReplaceInstallPrefix(dir, installPrefix); dir = @@ -2385,6 +2498,12 @@ private: cmGeneratorTarget::LinkClosure const* cmGeneratorTarget::GetLinkClosure( const std::string& config) const { + // There is no link implementation for targets that cannot compile sources. + if (!this->CanCompileSources()) { + static LinkClosure const empty = { {}, {} }; + return ∅ + } + std::string key(cmSystemTools::UpperCase(config)); auto i = this->LinkClosureMap.find(key); if (i == this->LinkClosureMap.end()) { @@ -2701,6 +2820,12 @@ const std::vector<const cmGeneratorTarget*>& cmGeneratorTarget::GetLinkImplementationClosure( const std::string& config) const { + // There is no link implementation for targets that cannot compile sources. + if (!this->CanCompileSources()) { + static std::vector<const cmGeneratorTarget*> const empty; + return empty; + } + LinkImplClosure& tgts = this->LinkImplClosureMap[config]; if (!tgts.Done) { tgts.Done = true; @@ -2708,6 +2833,7 @@ cmGeneratorTarget::GetLinkImplementationClosure( cmLinkImplementationLibraries const* impl = this->GetLinkImplementationLibraries(config); + assert(impl); for (cmLinkImplItem const& lib : impl->Libraries) { processILibs(config, this, lib, @@ -2757,29 +2883,26 @@ cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target) this->CurrentEntry = nullptr; // Queue all the source files already specified for the target. - if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - std::set<cmSourceFile*> emitted; - std::vector<std::string> const& configs = - this->Makefile->GetGeneratorConfigs(); - for (std::string const& c : configs) { - std::vector<cmSourceFile*> sources; - this->GeneratorTarget->GetSourceFiles(sources, c); - for (cmSourceFile* sf : sources) { - const std::set<cmGeneratorTarget const*> tgts = - this->GlobalGenerator->GetFilenameTargetDepends(sf); - 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 " - "is a dependency loop and is not allowed."; - this->GeneratorTarget->LocalGenerator->IssueMessage( - MessageType::FATAL_ERROR, e.str()); - return; - } - if (emitted.insert(sf).second && - this->SourcesQueued.insert(sf).second) { - this->SourceQueue.push(sf); - } + std::set<cmSourceFile*> emitted; + std::vector<std::string> const& configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + for (std::string const& c : configs) { + std::vector<cmSourceFile*> sources; + this->GeneratorTarget->GetSourceFiles(sources, c); + for (cmSourceFile* sf : sources) { + const std::set<cmGeneratorTarget const*> tgts = + this->GlobalGenerator->GetFilenameTargetDepends(sf); + 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 " + "is a dependency loop and is not allowed."; + this->GeneratorTarget->LocalGenerator->IssueMessage( + MessageType::FATAL_ERROR, e.str()); + return; + } + if (emitted.insert(sf).second && this->SourcesQueued.insert(sf).second) { + this->SourceQueue.push(sf); } } } @@ -2971,7 +3094,7 @@ void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc) // Queue the custom command dependencies. std::set<std::string> emitted; std::vector<std::string> const& configs = - this->Makefile->GetGeneratorConfigs(); + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); for (std::string const& conf : configs) { this->FollowCommandDepends(cc, conf, emitted); } @@ -3111,7 +3234,7 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const } else { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, - "Uknown CUDA architecture specifier \"" + std::string(specifier) + + "Unknown CUDA architecture specifier \"" + std::string(specifier) + "\"."); } } @@ -3360,23 +3483,24 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( &dagChecker, entries); if (this->Makefile->IsOn("APPLE")) { - cmLinkImplementationLibraries const* impl = - this->GetLinkImplementationLibraries(config); - for (cmLinkImplItem const& lib : impl->Libraries) { - std::string libDir = cmSystemTools::CollapseFullPath( - lib.AsStr(), this->Makefile->GetHomeOutputDirectory()); - - static cmsys::RegularExpression frameworkCheck( - "(.*\\.framework)(/Versions/[^/]+)?/[^/]+$"); - if (!frameworkCheck.find(libDir)) { - continue; - } + if (cmLinkImplementationLibraries const* impl = + this->GetLinkImplementationLibraries(config)) { + for (cmLinkImplItem const& lib : impl->Libraries) { + std::string libDir = cmSystemTools::CollapseFullPath( + lib.AsStr(), this->Makefile->GetHomeOutputDirectory()); + + static cmsys::RegularExpression frameworkCheck( + "(.*\\.framework)(/Versions/[^/]+)?/[^/]+$"); + if (!frameworkCheck.find(libDir)) { + continue; + } - libDir = frameworkCheck.match(1); + libDir = frameworkCheck.match(1); - EvaluatedTargetPropertyEntry ee(lib, cmListFileBacktrace()); - ee.Values.emplace_back(std::move(libDir)); - entries.Entries.emplace_back(std::move(ee)); + EvaluatedTargetPropertyEntry ee(lib, cmListFileBacktrace()); + ee.Values.emplace_back(std::move(libDir)); + entries.Entries.emplace_back(std::move(ee)); + } } } @@ -3827,7 +3951,7 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config, cmStrCat(generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(), "/CMakeFiles/", generatorTarget->GetName(), ".dir/cmake_pch"); - // For GCC the source extension will be tranformed into .h[xx].gch + // For GCC the source extension will be transformed into .h[xx].gch if (!this->Makefile->IsOn("CMAKE_LINK_PCH")) { const std::map<std::string, std::string> languageToExtension = { { "C", ".h.c" }, @@ -4414,12 +4538,75 @@ void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const { + // Compute the language standard based on the compile features. + cmStandardLevelResolver standardResolver(this->Makefile); std::vector<BT<std::string>> features = this->GetCompileFeatures(config); for (BT<std::string> const& f : features) { - if (!this->Makefile->AddRequiredTargetFeature(this->Target, f.Value)) { + std::string lang; + if (!standardResolver.CompileFeatureKnown(this->Target->GetName(), f.Value, + lang, nullptr)) { + return false; + } + + std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang); + cmProp currentLanguageStandard = this->GetLanguageStandard(lang, config); + + std::string newRequiredStandard; + if (!standardResolver.GetNewRequiredStandard( + this->Target->GetName(), f.Value, currentLanguageStandard, + newRequiredStandard)) { return false; } + + if (!newRequiredStandard.empty()) { + BTs<std::string>& languageStandardProperty = + this->LanguageStandardMap[key]; + if (languageStandardProperty.Value != newRequiredStandard) { + languageStandardProperty.Value = newRequiredStandard; + languageStandardProperty.Backtraces.clear(); + } + languageStandardProperty.Backtraces.emplace_back(f.Backtrace); + } + } + + return true; +} + +bool cmGeneratorTarget::ComputeCompileFeatures( + std::string const& config, std::set<LanguagePair> const& languagePairs) const +{ + for (const auto& language : languagePairs) { + BTs<std::string> const* generatorTargetLanguageStandard = + this->GetLanguageStandardProperty(language.first, config); + if (!generatorTargetLanguageStandard) { + // If the standard isn't explicitly set we copy it over from the + // specified paired language. + std::string key = + cmStrCat(cmSystemTools::UpperCase(config), '-', language.first); + BTs<std::string> const* standardToCopy = + this->GetLanguageStandardProperty(language.second, config); + if (standardToCopy != nullptr) { + this->LanguageStandardMap[key] = *standardToCopy; + generatorTargetLanguageStandard = &this->LanguageStandardMap[key]; + } else { + cmProp defaultStandard = this->Makefile->GetDef( + cmStrCat("CMAKE_", language.second, "_STANDARD_DEFAULT")); + if (defaultStandard != nullptr) { + this->LanguageStandardMap[key] = BTs<std::string>(*defaultStandard); + generatorTargetLanguageStandard = &this->LanguageStandardMap[key]; + } + } + + // Custom updates for the CUDA standard. + if (generatorTargetLanguageStandard != nullptr && + language.first == "CUDA") { + if (generatorTargetLanguageStandard->Value == "98") { + this->LanguageStandardMap[key].Value = "03"; + } + } + } } + return true; } @@ -5297,8 +5484,7 @@ bool getTypedProperty<bool>(cmGeneratorTarget const* tgt, } cmProp value = tgt->GetProperty(prop); - return cmIsOn( - genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop)); + return cmIsOn(genexInterpreter->Evaluate(value ? *value : "", prop)); } template <> @@ -5312,8 +5498,7 @@ const char* getTypedProperty<const char*>( return value ? value->c_str() : nullptr; } - return genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop) - .c_str(); + return genexInterpreter->Evaluate(value ? *value : "", prop).c_str(); } template <> @@ -5327,7 +5512,7 @@ std::string getTypedProperty<std::string>( return valueAsString(value ? value->c_str() : nullptr); } - return genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop); + return genexInterpreter->Evaluate(value ? *value : "", prop); } template <typename PropertyType> @@ -5728,7 +5913,7 @@ std::string cmGeneratorTarget::GetRuntimeLinkLibrary( // not it is overridden by a property. cmProp runtimeLibraryDefault = this->Makefile->GetDef( cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT")); - if (!runtimeLibraryDefault || runtimeLibraryDefault->empty()) { + if (!cmNonempty(runtimeLibraryDefault)) { return std::string(); } cmProp runtimeLibraryValue = @@ -6410,15 +6595,20 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( iface.HadHeadSensitiveCondition, iface.HadContextSensitiveCondition, iface.HadLinkLanguageSensitiveCondition); - } else if (!cmp0022NEW) + return; + } + // If CMP0022 is NEW then the plain tll signature sets the // INTERFACE_LINK_LIBRARIES, so if we get here then the project // cleared the property explicitly and we should not fall back // to the link implementation. - { - // The link implementation is the default link interface. - cmLinkImplementationLibraries const* impl = - this->GetLinkImplementationLibrariesInternal(config, headTarget); + if (cmp0022NEW) { + return; + } + + // The link implementation is the default link interface. + if (cmLinkImplementationLibraries const* impl = + this->GetLinkImplementationLibrariesInternal(config, headTarget)) { iface.Libraries.insert(iface.Libraries.end(), impl->Libraries.begin(), impl->Libraries.end()); if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN && @@ -6712,8 +6902,8 @@ const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( const std::string& config, bool secondPass) const { - // There is no link implementation for imported targets. - if (this->IsImported()) { + // There is no link implementation for targets that cannot compile sources. + if (!this->CanCompileSources()) { return nullptr; } @@ -6737,7 +6927,7 @@ bool cmGeneratorTarget::GetConfigCommonSourceFiles( std::vector<cmSourceFile*>& files) const { std::vector<std::string> const& configs = - this->Makefile->GetGeneratorConfigs(); + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); auto it = configs.begin(); const std::string& firstConfig = *it; @@ -6861,7 +7051,7 @@ std::string cmGeneratorTarget::CheckCMP0004(std::string const& item) const bool cmGeneratorTarget::IsDeprecated() const { cmProp deprecation = this->GetProperty("DEPRECATION"); - return deprecation && !deprecation->empty(); + return cmNonempty(deprecation); } std::string cmGeneratorTarget::GetDeprecation() const @@ -6876,6 +7066,11 @@ std::string cmGeneratorTarget::GetDeprecation() const void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages, const std::string& config) const { + // Targets that do not compile anything have no languages. + if (!this->CanCompileSources()) { + return; + } + std::vector<cmSourceFile*> sourceFiles; this->GetSourceFiles(sourceFiles, config); for (cmSourceFile* src : sourceFiles) { @@ -6926,7 +7121,7 @@ bool cmGeneratorTarget::IsCSharpOnly() const // Consider an explicit linker language property, but *not* the // computed linker language that may depend on linked targets. cmProp linkLang = this->GetProperty("LINKER_LANGUAGE"); - if (linkLang && !linkLang->empty()) { + if (cmNonempty(linkLang)) { languages.insert(*linkLang); } return languages.size() == 1 && languages.count("CSharp") > 0; @@ -6971,8 +7166,8 @@ cmLinkImplementationLibraries const* cmGeneratorTarget::GetLinkImplementationLibrariesInternal( const std::string& config, cmGeneratorTarget const* head) const { - // There is no link implementation for imported targets. - if (this->IsImported()) { + // There is no link implementation for targets that cannot compile sources. + if (!this->CanCompileSources()) { return nullptr; } diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 3aedbf5..69c5faf 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -45,14 +45,22 @@ public: cmGlobalGenerator* GetGlobalGenerator() const; + bool IsInBuildSystem() const; bool IsImported() const; bool IsImportedGloballyVisible() const; + bool CanCompileSources() const; const std::string& GetLocation(const std::string& config) const; std::vector<cmCustomCommand> const& GetPreBuildCommands() const; std::vector<cmCustomCommand> const& GetPreLinkCommands() const; std::vector<cmCustomCommand> const& GetPostBuildCommands() const; + void AppendCustomCommandSideEffects( + std::set<cmGeneratorTarget const*>& sideEffects) const; + void AppendLanguageSideEffects( + std::map<std::string, std::set<cmGeneratorTarget const*>>& sideEffects) + const; + #define DECLARE_TARGET_POLICY(POLICY) \ cmPolicies::PolicyStatus GetPolicyStatus##POLICY() const \ { \ @@ -148,6 +156,16 @@ public: bool HasExplicitObjectName(cmSourceFile const* file) const; void AddExplicitObjectName(cmSourceFile const* sf); + BTs<std::string> const* GetLanguageStandardProperty( + std::string const& lang, std::string const& config) const; + + cmProp GetLanguageStandard(std::string const& lang, + std::string const& config) const; + + cmProp GetLanguageExtensions(std::string const& lang) const; + + bool GetLanguageStandardRequired(std::string const& lang) const; + void GetModuleDefinitionSources(std::vector<cmSourceFile const*>&, const std::string& config) const; void GetExternalObjects(std::vector<cmSourceFile const*>&, @@ -165,8 +183,8 @@ public: void ComputeObjectMapping(); - const char* GetFeature(const std::string& feature, - const std::string& config) const; + cmProp GetFeature(const std::string& feature, + const std::string& config) const; const char* GetLinkPIEProperty(const std::string& config) const; @@ -515,6 +533,11 @@ public: bool ComputeCompileFeatures(std::string const& config) const; + using LanguagePair = std::pair<std::string, std::string>; + bool ComputeCompileFeatures( + std::string const& config, + std::set<LanguagePair> const& languagePairs) const; + /** * Trace through the source files in this target and add al source files * that they depend on, used by all generators @@ -1038,6 +1061,11 @@ private: bool GetRPATH(const std::string& config, const std::string& prop, std::string& rpath) const; + mutable std::map<std::string, BTs<std::string>> LanguageStandardMap; + + cmProp GetPropertyWithPairedLanguageSupport(std::string const& lang, + const char* suffix) const; + public: const std::vector<const cmGeneratorTarget*>& GetLinkImplementationClosure( const std::string& config) const; diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx index 811421a..38bffbf 100644 --- a/Source/cmGetFilenameComponentCommand.cxx +++ b/Source/cmGetFilenameComponentCommand.cxx @@ -14,6 +14,7 @@ bool cmGetFilenameComponentCommand(std::vector<std::string> const& args, { if (args.size() < 3) { status.SetError("called with incorrect number of arguments"); + cmSystemTools::SetFatalErrorOccured(); return false; } @@ -114,6 +115,7 @@ bool cmGetFilenameComponentCommand(std::vector<std::string> const& args, } else { std::string err = "unknown component " + args[2]; status.SetError(err); + cmSystemTools::SetFatalErrorOccured(); return false; } diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx index cba7704..cdfd8c8 100644 --- a/Source/cmGetPropertyCommand.cxx +++ b/Source/cmGetPropertyCommand.cxx @@ -17,7 +17,6 @@ #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" -#include "cmTargetPropertyComputer.h" #include "cmTest.h" #include "cmake.h" @@ -364,12 +363,9 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name, cmProp prop_cstr = nullptr; cmListFileBacktrace bt = status.GetMakefile().GetBacktrace(); cmMessenger* messenger = status.GetMakefile().GetMessenger(); - if (cmTargetPropertyComputer::PassesWhitelist( - target->GetType(), propertyName, messenger, bt)) { - prop_cstr = target->GetComputedProperty(propertyName, messenger, bt); - if (!prop_cstr) { - prop_cstr = target->GetProperty(propertyName); - } + prop_cstr = target->GetComputedProperty(propertyName, messenger, bt); + if (!prop_cstr) { + prop_cstr = target->GetProperty(propertyName); } return StoreResult(infoType, status.GetMakefile(), variable, prop_cstr ? prop_cstr->c_str() : nullptr); diff --git a/Source/cmGetTargetPropertyCommand.cxx b/Source/cmGetTargetPropertyCommand.cxx index 8a304be..78a17d2 100644 --- a/Source/cmGetTargetPropertyCommand.cxx +++ b/Source/cmGetTargetPropertyCommand.cxx @@ -12,7 +12,6 @@ #include "cmPolicies.h" #include "cmProperty.h" #include "cmTarget.h" -#include "cmTargetPropertyComputer.h" class cmMessenger; @@ -46,12 +45,9 @@ bool cmGetTargetPropertyCommand(std::vector<std::string> const& args, cmProp prop_cstr = nullptr; cmListFileBacktrace bt = mf.GetBacktrace(); cmMessenger* messenger = mf.GetMessenger(); - if (cmTargetPropertyComputer::PassesWhitelist(tgt->GetType(), args[2], - messenger, bt)) { - prop_cstr = tgt->GetComputedProperty(args[2], messenger, bt); - if (!prop_cstr) { - prop_cstr = tgt->GetProperty(args[2]); - } + prop_cstr = tgt->GetComputedProperty(args[2], messenger, bt); + if (!prop_cstr) { + prop_cstr = tgt->GetProperty(args[2]); } if (prop_cstr) { prop = *prop_cstr; diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index 97580d6..1589c47 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -550,10 +550,9 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj) */ for (auto& sg : groupFilesList) { std::ostream* fout; - cmProp noSourceGroupFile = - this->GeneratorTarget->GetProperty("GHS_NO_SOURCE_GROUP_FILE"); - bool useProjectFile = (noSourceGroupFile && cmIsOn(*noSourceGroupFile)) || - cmIsOn(this->Makefile->GetDefinition("CMAKE_GHS_NO_SOURCE_GROUP_FILE")); + bool useProjectFile = + cmIsOn(this->GeneratorTarget->GetProperty("GHS_NO_SOURCE_GROUP_FILE")) || + this->Makefile->IsOn("CMAKE_GHS_NO_SOURCE_GROUP_FILE"); if (useProjectFile || sg.empty()) { fout = &fout_proj; } else { diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h index f03ca44..5f26387 100644 --- a/Source/cmGhsMultiTargetGenerator.h +++ b/Source/cmGhsMultiTargetGenerator.h @@ -43,7 +43,7 @@ private: void SetCompilerFlags(std::string const& config, const std::string& language); - std::string GetDefines(const std::string& langugae, + std::string GetDefines(const std::string& language, std::string const& config); void WriteIncludes(std::ostream& fout, const std::string& config, diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx index 9dc86f4..9e5bbca 100644 --- a/Source/cmGlobalCommonGenerator.cxx +++ b/Source/cmGlobalCommonGenerator.cxx @@ -5,8 +5,12 @@ #include <memory> #include <utility> +#include <cmext/algorithm> + +#include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmLocalGenerator.h" +#include "cmMakefile.h" #include "cmProperty.h" #include "cmStateDirectory.h" #include "cmStateSnapshot.h" @@ -31,26 +35,30 @@ cmGlobalCommonGenerator::ComputeDirectoryTargets() const lg->GetStateSnapshot().GetDirectory().GetCurrentBinary()); DirectoryTarget& dirTarget = dirTargets[currentBinaryDir]; dirTarget.LG = lg.get(); + const std::vector<std::string>& configs = + lg->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); // The directory-level rule should depend on the target-level rules // for all targets in the directory. for (const auto& gt : lg->GetGeneratorTargets()) { cmStateEnums::TargetType const type = gt->GetType(); - if (type != cmStateEnums::EXECUTABLE && - type != cmStateEnums::STATIC_LIBRARY && - type != cmStateEnums::SHARED_LIBRARY && - type != cmStateEnums::MODULE_LIBRARY && - type != cmStateEnums::OBJECT_LIBRARY && - type != cmStateEnums::UTILITY) { + if (type == cmStateEnums::GLOBAL_TARGET || !gt->IsInBuildSystem()) { continue; } DirectoryTarget::Target t; t.GT = gt.get(); - if (cmProp exclude = gt->GetProperty("EXCLUDE_FROM_ALL")) { - if (cmIsOn(*exclude)) { - // This target has been explicitly excluded. - t.ExcludeFromAll = true; - } else { + const std::string EXCLUDE_FROM_ALL("EXCLUDE_FROM_ALL"); + if (cmProp exclude = gt->GetProperty(EXCLUDE_FROM_ALL)) { + for (const std::string& config : configs) { + cmGeneratorExpressionInterpreter genexInterpreter(lg.get(), config, + gt.get()); + if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) { + // This target has been explicitly excluded. + t.ExcludedFromAllInConfigs.push_back(config); + } + } + + if (t.ExcludedFromAllInConfigs.empty()) { // This target has been explicitly un-excluded. The directory-level // rule for every directory between this and the root should depend // on the target-level rule for this target. @@ -78,3 +86,12 @@ cmGlobalCommonGenerator::ComputeDirectoryTargets() const return dirTargets; } + +bool cmGlobalCommonGenerator::IsExcludedFromAllInConfig( + const DirectoryTarget::Target& t, const std::string& config) +{ + if (this->IsMultiConfig()) { + return cm::contains(t.ExcludedFromAllInConfigs, config); + } + return !t.ExcludedFromAllInConfigs.empty(); +} diff --git a/Source/cmGlobalCommonGenerator.h b/Source/cmGlobalCommonGenerator.h index 7d16dac..f97b5f4 100644 --- a/Source/cmGlobalCommonGenerator.h +++ b/Source/cmGlobalCommonGenerator.h @@ -30,7 +30,7 @@ public: struct Target { cmGeneratorTarget const* GT = nullptr; - bool ExcludeFromAll = false; + std::vector<std::string> ExcludedFromAllInConfigs; }; std::vector<Target> Targets; struct Dir @@ -41,6 +41,8 @@ public: std::vector<Dir> Children; }; std::map<std::string, DirectoryTarget> ComputeDirectoryTargets() const; + bool IsExcludedFromAllInConfig(const DirectoryTarget::Target& t, + const std::string& config); }; #endif diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 4dc4092..cad5d1f 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -235,6 +235,14 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang, } cmProp cname = this->GetCMakeInstance()->GetState()->GetInitializedCacheValue(langComp); + + // Split compiler from arguments + std::vector<std::string> cnameArgVec; + if (cname && !cname->empty()) { + cmExpandList(*cname, cnameArgVec); + cname = &cnameArgVec.front(); + } + std::string changeVars; if (cname && !optional) { std::string cnameString; @@ -302,31 +310,12 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const bool failed = false; for (const auto& localGen : this->LocalGenerators) { for (const auto& target : localGen->GetGeneratorTargets()) { - if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET || - target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY || - target->GetType() == cmStateEnums::TargetType::UTILITY) { + if (!target->CanCompileSources() || + cmIsOn(target->GetProperty("ghs_integrity_app"))) { continue; } - if (cmProp p = target->GetProperty("ghs_integrity_app")) { - if (cmIsOn(*p)) { - continue; - } - } - std::vector<std::string> configs; - target->Makefile->GetConfigurations(configs); - std::vector<cmSourceFile*> srcs; - if (configs.empty()) { - target->GetSourceFiles(srcs, ""); - } else { - for (std::string const& config : configs) { - target->GetSourceFiles(srcs, config); - if (!srcs.empty()) { - break; - } - } - } - if (srcs.empty()) { + if (target->GetAllConfigSources().empty()) { std::ostringstream e; e << "No SOURCES given to target: " << target->GetName(); this->GetCMakeInstance()->IssueMessage( @@ -349,7 +338,8 @@ bool cmGlobalGenerator::CheckTargetsForType() const if (target->GetType() == cmStateEnums::EXECUTABLE && target->GetPropertyAsBool("WIN32_EXECUTABLE")) { std::vector<std::string> const& configs = - target->Makefile->GetGeneratorConfigs(); + target->Makefile->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig); for (std::string const& config : configs) { if (target->GetLinkerLanguage(config) == "Swift") { this->GetCMakeInstance()->IssueMessage( @@ -374,16 +364,10 @@ bool cmGlobalGenerator::CheckTargetsForPchCompilePdb() const bool failed = false; for (const auto& generator : this->LocalGenerators) { for (const auto& target : generator->GetGeneratorTargets()) { - if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET || - target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY || - target->GetType() == cmStateEnums::TargetType::UTILITY) { + if (!target->CanCompileSources() || + cmIsOn(target->GetProperty("ghs_integrity_app"))) { continue; } - if (cmProp p = target->GetProperty("ghs_integrity_app")) { - if (cmIsOn(*p)) { - continue; - } - } std::string const& reuseFrom = target->GetSafeProperty("PRECOMPILE_HEADERS_REUSE_FROM"); @@ -425,15 +409,13 @@ bool cmGlobalGenerator::FindMakeProgram(cmMakefile* mf) "all generators must specify this->FindMakeProgramFile"); return false; } - if (!mf->GetDefinition("CMAKE_MAKE_PROGRAM") || - cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) { + if (cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) { std::string setMakeProgram = mf->GetModulesFile(this->FindMakeProgramFile); if (!setMakeProgram.empty()) { mf->ReadListFile(setMakeProgram); } } - if (!mf->GetDefinition("CMAKE_MAKE_PROGRAM") || - cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) { + if (cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) { std::ostringstream err; err << "CMake was unable to find a build program corresponding to \"" << this->GetName() << "\". CMAKE_MAKE_PROGRAM is not set. You " @@ -596,6 +578,16 @@ void cmGlobalGenerator::EnableLanguage( mf->ReadListFile(fpath); } } + + if (readCMakeSystem) { + // Find the native build tool for this generator. + // This has to be done early so that MSBuild can be used to examine the + // cross-compilation environment. + if (!this->FindMakeProgram(mf)) { + return; + } + } + // Load the CMakeDetermineSystem.cmake file and find out // what platform we are running on if (!mf->GetDefinition("CMAKE_SYSTEM")) { @@ -667,11 +659,6 @@ void cmGlobalGenerator::EnableLanguage( cmSystemTools::SetFatalErrorOccured(); return; } - - // Find the native build tool for this generator. - if (!this->FindMakeProgram(mf)) { - return; - } } // Check that the languages are supported by the generator and its @@ -794,7 +781,7 @@ void cmGlobalGenerator::EnableLanguage( std::string compilerEnv = cmStrCat("CMAKE_", lang, "_COMPILER_ENV_VAR"); std::ostringstream noCompiler; const char* compilerFile = mf->GetDefinition(compilerName); - if (!compilerFile || !*compilerFile || cmIsNOTFOUND(compilerFile)) { + if (!cmNonempty(compilerFile) || cmIsNOTFOUND(compilerFile)) { /* clang-format off */ noCompiler << "No " << compilerName << " could be found.\n" @@ -1442,12 +1429,10 @@ bool cmGlobalGenerator::Compute() localGen->AddHelperCommands(); } - // Finalize the set of compile features for each target. - // FIXME: This turns into calls to cmMakefile::AddRequiredTargetFeature - // which actually modifies the <lang>_STANDARD target property - // on the original cmTarget instance. It accumulates features - // across all configurations. Some refactoring is needed to - // compute a per-config resulta purely during generation. + // Perform up-front computation in order to handle errors (such as unknown + // features) at this point. While processing the compile features we also + // calculate and cache the language standard required by the compile + // features. for (const auto& localGen : this->LocalGenerators) { if (!localGen->ComputeTargetCompileFeatures()) { return false; @@ -1612,9 +1597,7 @@ bool cmGlobalGenerator::AddAutomaticSources() for (const auto& lg : this->LocalGenerators) { lg->CreateEvaluationFileOutputs(); for (const auto& gt : lg->GetGeneratorTargets()) { - if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY || - gt->GetType() == cmStateEnums::UTILITY || - gt->GetType() == cmStateEnums::GLOBAL_TARGET) { + if (!gt->CanCompileSources()) { continue; } lg->AddUnityBuild(gt.get()); @@ -1626,9 +1609,7 @@ bool cmGlobalGenerator::AddAutomaticSources() } for (const auto& lg : this->LocalGenerators) { for (const auto& gt : lg->GetGeneratorTargets()) { - if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY || - gt->GetType() == cmStateEnums::UTILITY || - gt->GetType() == cmStateEnums::GLOBAL_TARGET) { + if (!gt->CanCompileSources()) { continue; } // Handle targets that re-use a PCH from an above-handled target. @@ -1698,8 +1679,8 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo() cmPolicies::PolicyStatus polSt = mf->GetPolicyStatus(cmPolicies::CMP0043); if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) { - std::vector<std::string> configs; - mf->GetConfigurations(configs); + std::vector<std::string> configs = + mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig); for (std::string const& c : configs) { std::string defPropName = @@ -1988,8 +1969,9 @@ int cmGlobalGenerator::Build( std::string makeCommandStr; output += "\nRun Build Command(s):"; - for (auto command = makeCommand.begin(); command != makeCommand.end(); - ++command) { + retVal = 0; + for (auto command = makeCommand.begin(); + command != makeCommand.end() && retVal == 0; ++command) { makeCommandStr = command->Printable(); if (command != makeCommand.end()) { makeCommandStr += " && "; @@ -2179,13 +2161,38 @@ bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root, } bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root, - cmGeneratorTarget* target) const + const cmGeneratorTarget* target) const { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!target->IsInBuildSystem()) { return true; } - if (cmProp exclude = target->GetProperty("EXCLUDE_FROM_ALL")) { - return cmIsOn(*exclude); + cmMakefile* mf = root->GetMakefile(); + const std::string EXCLUDE_FROM_ALL = "EXCLUDE_FROM_ALL"; + if (cmProp exclude = target->GetProperty(EXCLUDE_FROM_ALL)) { + // Expand the property value per configuration. + unsigned int trueCount = 0; + unsigned int falseCount = 0; + const std::vector<std::string>& configs = + mf->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + for (const std::string& config : configs) { + cmGeneratorExpressionInterpreter genexInterpreter(root, config, target); + if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) { + ++trueCount; + } else { + ++falseCount; + } + } + + // Check whether the genex expansion of the property agrees in all + // configurations. + if (trueCount && falseCount) { + std::ostringstream e; + e << "The EXCLUDE_FROM_ALL property of target \"" << target->GetName() + << "\" varies by configuration. This is not supported by the \"" + << root->GetGlobalGenerator()->GetName() << "\" generator."; + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); + } + return trueCount; } // This target is included in its directory. Check whether the // directory is excluded. @@ -2445,7 +2452,7 @@ void cmGlobalGenerator::AddGlobalTarget_Package( gti.WorkingDir = mf->GetCurrentBinaryDirectory(); cmCustomCommandLine singleLine; singleLine.push_back(cmSystemTools::GetCPackCommand()); - if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') { + if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') { singleLine.push_back("-C"); singleLine.push_back(cmakeCfgIntDir); } @@ -2530,7 +2537,7 @@ void cmGlobalGenerator::AddGlobalTarget_Test( singleLine.push_back(arg); } } - if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') { + if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') { singleLine.push_back("-C"); singleLine.push_back(cmakeCfgIntDir); } else // TODO: This is a hack. Should be something to do with the @@ -2611,7 +2618,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install( "installation rules have been specified", mf->GetBacktrace()); } else if (this->InstallTargetEnabled && !skipInstallRules) { - if (!cmakeCfgIntDir || !*cmakeCfgIntDir || cmakeCfgIntDir[0] == '.') { + if (!(cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.')) { std::set<std::string>* componentsSet = &this->InstallComponents; std::ostringstream ostr; if (!componentsSet->empty()) { @@ -2650,7 +2657,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install( cmd = "cmake"; } singleLine.push_back(cmd); - if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') { + if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') { std::string cfgArg = "-DBUILD_TYPE="; bool useEPN = this->UseEffectivePlatformName(mf.get()); if (useEPN) { @@ -3045,7 +3052,7 @@ void cmGlobalGenerator::WriteSummary() for (const auto& lg : this->LocalGenerators) { for (const auto& tgt : lg->GetGeneratorTargets()) { - if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!tgt->IsInBuildSystem()) { continue; } this->WriteSummary(tgt.get()); @@ -3123,7 +3130,8 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target) fout << "# Source files and their labels\n"; std::vector<cmSourceFile*> sources; std::vector<std::string> const& configs = - target->Target->GetMakefile()->GetGeneratorConfigs(); + target->Target->GetMakefile()->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig); for (std::string const& c : configs) { target->GetSourceFiles(sources, c); } @@ -3222,8 +3230,9 @@ bool cmGlobalGenerator::GenerateCPackPropertiesFile() const auto& lg = this->LocalGenerators[0]; cmMakefile* mf = lg->GetMakefile(); - std::vector<std::string> configs; - std::string config = mf->GetConfigurations(configs, false); + std::vector<std::string> configs = + mf->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig); + std::string config = mf->GetDefaultConfiguration(); std::string path = cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), "/CPackProperties.cmake"); diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 57c7808..c2c80c2 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -542,7 +542,8 @@ protected: bool IsExcluded(cmStateSnapshot const& root, cmStateSnapshot const& snp) const; bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen) const; - bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) const; + bool IsExcluded(cmLocalGenerator* root, + const cmGeneratorTarget* target) const; virtual void InitializeProgressMarks() {} struct GlobalTargetInfo diff --git a/Source/cmGlobalGeneratorFactory.h b/Source/cmGlobalGeneratorFactory.h index 3709365..13cfe4d 100644 --- a/Source/cmGlobalGeneratorFactory.h +++ b/Source/cmGlobalGeneratorFactory.h @@ -44,7 +44,7 @@ public: /** Get the list of supported platforms name for this generator */ virtual std::vector<std::string> GetKnownPlatforms() const = 0; - /** If the generator suports platforms, get its default. */ + /** If the generator supports platforms, get its default. */ virtual std::string GetDefaultPlatformName() const = 0; }; diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index d36adfb..7c87131 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -218,10 +218,11 @@ void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd, { const char* ghsRoot = mf->GetDefinition("GHS_TOOLSET_ROOT"); - if (!ghsRoot || ghsRoot[0] == '\0') { - ghsRoot = DEFAULT_TOOLSET_ROOT; + if (cmNonempty(ghsRoot)) { + tsd = ghsRoot; + } else { + tsd = DEFAULT_TOOLSET_ROOT; } - tsd = ghsRoot; if (ts.empty()) { std::vector<std::string> output; @@ -467,11 +468,10 @@ void cmGlobalGhsMultiGenerator::WriteAllTarget( this->ProjectTargets.push_back(t); } for (cmGeneratorTarget const* t : sortedProjectTargets) { - if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!t->IsInBuildSystem()) { continue; } - cmProp p = t->GetProperty("EXCLUDE_FROM_ALL"); - if (!(p && cmIsOn(*p))) { + if (!IsExcluded(t->GetLocalGenerator(), t)) { defaultTargets.push_back(t); } } @@ -635,7 +635,7 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives( std::string tgt; const char* t = this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET"); - if (t && *t != '\0') { + if (cmNonempty(t)) { tgt = t; this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET"); } else { diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 843b0f4..f0fa1f4 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -5,9 +5,9 @@ #include <algorithm> #include <cctype> #include <cstdio> -#include <iterator> #include <sstream> +#include <cm/iterator> #include <cm/memory> #include <cmext/algorithm> #include <cmext/memory> @@ -518,7 +518,8 @@ void cmGlobalNinjaGenerator::Generate() if (cmSystemTools::GetErrorOccuredFlag()) { this->RulesFileStream->setstate(std::ios::failbit); - for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig)) { this->GetImplFileStream(config)->setstate(std::ios::failbit); this->GetConfigFileStream(config)->setstate(std::ios::failbit); } @@ -1092,6 +1093,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( } // FALLTHROUGH case cmStateEnums::GLOBAL_TARGET: + case cmStateEnums::INTERFACE_LIBRARY: case cmStateEnums::UTILITY: { std::string path = cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/', @@ -1104,8 +1106,8 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( break; } - default: - return; + case cmStateEnums::UNKNOWN_LIBRARY: + break; } } @@ -1127,7 +1129,7 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( cmNinjaDeps outs; for (cmTargetDepend const& targetDep : this->GetTargetDirectDepends(target)) { - if (targetDep->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!targetDep->IsInBuildSystem()) { continue; } if (targetDep.IsCross()) { @@ -1169,7 +1171,7 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure( cmNinjaOuts this_outs; // this will be the new cache entry for (auto const& dep_target : this->GetTargetDirectDepends(target)) { - if (dep_target->GetType() == cmStateEnums::INTERFACE_LIBRARY || + if (!dep_target->IsInBuildSystem() || (this->EnableCrossConfigBuild() && !dep_target.IsCross())) { continue; } @@ -1188,7 +1190,7 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure( // finally generate the outputs of the target itself, if applicable cmNinjaDeps outs; if (!omit_self) { - this->AppendTargetOutputs(target, outs, config); + this->AppendTargetOutputs(target, outs, config, DependOnTargetArtifact); } outputs.insert(outs.begin(), outs.end()); } @@ -1200,14 +1202,15 @@ void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias, std::string outputPath = this->NinjaOutputPath(alias); std::string buildAlias = this->BuildAlias(outputPath, config); cmNinjaDeps outputs; - this->AppendTargetOutputs(target, outputs, config); + this->AppendTargetOutputs(target, outputs, config, DependOnTargetArtifact); // Mark the target's outputs as ambiguous to ensure that no other target // uses the output as an alias. for (std::string const& output : outputs) { this->TargetAliases[output].GeneratorTarget = nullptr; this->DefaultTargetAliases[output].GeneratorTarget = nullptr; for (const std::string& config2 : - this->Makefiles.front()->GetGeneratorConfigs()) { + this->Makefiles.front()->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig)) { this->Configs[config2].TargetAliases[output].GeneratorTarget = nullptr; } } @@ -1265,11 +1268,12 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) if (ta.second.Config == "all") { for (auto const& config : this->CrossConfigs) { this->AppendTargetOutputs(ta.second.GeneratorTarget, - build.ExplicitDeps, config); + build.ExplicitDeps, config, + DependOnTargetArtifact); } } else { this->AppendTargetOutputs(ta.second.GeneratorTarget, build.ExplicitDeps, - ta.second.Config); + ta.second.Config, DependOnTargetArtifact); } this->WriteBuild(this->EnableCrossConfigBuild() && (ta.second.Config == "all" || @@ -1280,7 +1284,8 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) } if (this->IsMultiConfig()) { - for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs()) { + for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig)) { for (auto const& ta : this->Configs[config].TargetAliases) { // Don't write ambiguous aliases. if (!ta.second.GeneratorTarget) { @@ -1296,7 +1301,8 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) build.Outputs.front() = ta.first; build.ExplicitDeps.clear(); this->AppendTargetOutputs(ta.second.GeneratorTarget, - build.ExplicitDeps, config); + build.ExplicitDeps, config, + DependOnTargetArtifact); this->WriteBuild(*this->GetConfigFileStream(config), build); } } @@ -1318,7 +1324,8 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) build.ExplicitDeps.clear(); for (auto const& config : this->DefaultConfigs) { this->AppendTargetOutputs(ta.second.GeneratorTarget, - build.ExplicitDeps, config); + build.ExplicitDeps, config, + DependOnTargetArtifact); } this->WriteBuild(*this->GetDefaultFileStream(), build); } @@ -1339,11 +1346,9 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) cmGlobalNinjaGenerator::WriteDivider(os); std::string const& currentBinaryDir = it.first; DirectoryTarget const& dt = it.second; - std::vector<std::string> configs; - dt.LG->GetMakefile()->GetConfigurations(configs, true); - if (configs.empty()) { - configs.emplace_back(); - } + std::vector<std::string> configs = + dt.LG->GetMakefile()->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig); // Setup target cmNinjaDeps configDeps; @@ -1356,8 +1361,9 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) build.Outputs.front() = this->BuildAlias(buildDirAllTarget, config); configDeps.emplace_back(build.Outputs.front()); for (DirectoryTarget::Target const& t : dt.Targets) { - if (!t.ExcludeFromAll) { - this->AppendTargetOutputs(t.GT, build.ExplicitDeps, config); + if (!IsExcludedFromAllInConfig(t, config)) { + this->AppendTargetOutputs(t.GT, build.ExplicitDeps, config, + DependOnTargetArtifact); } } for (DirectoryTarget::Dir const& d : dt.Children) { @@ -1538,7 +1544,8 @@ void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os) this->WriteTargetClean(os); this->WriteTargetHelp(os); - for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig)) { this->WriteTargetDefault(*this->GetConfigFileStream(config)); } @@ -1712,11 +1719,8 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) std::string cleanScriptRel = "CMakeFiles/clean_additional.cmake"; std::string cleanScriptAbs = cmStrCat(lgr->GetBinaryDirectory(), '/', cleanScriptRel); - std::vector<std::string> configs; - this->Makefiles[0]->GetConfigurations(configs, true); - if (configs.empty()) { - configs.emplace_back(); - } + std::vector<std::string> configs = + this->Makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); // Check if there are additional files to clean bool empty = true; @@ -1810,7 +1814,8 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) WriteRule(*this->RulesFileStream, rule); } - auto const configs = this->Makefiles.front()->GetGeneratorConfigs(); + auto const configs = this->Makefiles.front()->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig); // Write build { @@ -2489,7 +2494,8 @@ bool cmGlobalNinjaMultiGenerator::OpenBuildFileStreams() << "# This file contains build statements common to all " "configurations.\n\n"; - for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig)) { // Open impl file. if (!this->OpenFileStream(this->ImplFileStreams[config], GetNinjaImplFilename(config))) { @@ -2529,7 +2535,8 @@ void cmGlobalNinjaMultiGenerator::CloseBuildFileStreams() this->DefaultFileStream.reset(); } // No error if it wasn't open - for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) { + for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig)) { if (this->ImplFileStreams[config]) { this->ImplFileStreams[config].reset(); } else { @@ -2571,7 +2578,8 @@ std::string cmGlobalNinjaMultiGenerator::GetNinjaConfigFilename( void cmGlobalNinjaMultiGenerator::AddRebuildManifestOutputs( cmNinjaDeps& outputs) const { - for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs()) { + for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig)) { outputs.push_back(this->NinjaOutputPath(GetNinjaImplFilename(config))); outputs.push_back(this->NinjaOutputPath(GetNinjaConfigFilename(config))); } @@ -2583,11 +2591,9 @@ void cmGlobalNinjaMultiGenerator::AddRebuildManifestOutputs( void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs( std::vector<std::string>& configs) const { - auto const oldSize = configs.size(); - this->Makefiles.front()->GetConfigurations(configs); - if (configs.size() == oldSize) { - configs.emplace_back(); - } + auto allConfigs = + this->Makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + configs.insert(configs.end(), cm::cbegin(allConfigs), cm::cend(allConfigs)); } bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables() diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 44e632f..10f5cf6 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -318,14 +318,13 @@ public: virtual std::string OrderDependsTargetForTarget( cmGeneratorTarget const* target, const std::string& config) const; - void AppendTargetOutputs( - cmGeneratorTarget const* target, cmNinjaDeps& outputs, - const std::string& config, - cmNinjaTargetDepends depends = DependOnTargetArtifact); - void AppendTargetDepends( - cmGeneratorTarget const* target, cmNinjaDeps& outputs, - const std::string& config, const std::string& fileConfig, - cmNinjaTargetDepends depends = DependOnTargetArtifact); + void AppendTargetOutputs(cmGeneratorTarget const* target, + cmNinjaDeps& outputs, const std::string& config, + cmNinjaTargetDepends depends); + void AppendTargetDepends(cmGeneratorTarget const* target, + cmNinjaDeps& outputs, const std::string& config, + const std::string& fileConfig, + cmNinjaTargetDepends depends); void AppendTargetDependsClosure(cmGeneratorTarget const* target, cmNinjaDeps& outputs, const std::string& config); diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index c31983b..37a77fa 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -143,7 +143,7 @@ void cmGlobalUnixMakefileGenerator3::Generate() total += pmi.second.NumberOfActions; } - // write each target's progress.make this loop is done twice. Bascially the + // write each target's progress.make this loop is done twice. Basically the // Generate pass counts all the actions, the first loop below determines // how many actions have progress updates for each target and writes to // corrrect variable values for everything except the all targets. The @@ -387,12 +387,8 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules( cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(lGenerator); // for all of out targets for (const auto& tgt : lg.GetGeneratorTargets()) { - if ((tgt->GetType() == cmStateEnums::EXECUTABLE) || - (tgt->GetType() == cmStateEnums::STATIC_LIBRARY) || - (tgt->GetType() == cmStateEnums::SHARED_LIBRARY) || - (tgt->GetType() == cmStateEnums::MODULE_LIBRARY) || - (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) || - (tgt->GetType() == cmStateEnums::UTILITY)) { + if (tgt->IsInBuildSystem() && + tgt->GetType() != cmStateEnums::GLOBAL_TARGET) { std::string tname = cmStrCat(lg.GetRelativeTargetDirectory(tgt.get()), "/DependInfo.cmake"); cmSystemTools::ConvertToUnixSlashes(tname); @@ -416,7 +412,7 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2( std::vector<std::string> depends; for (DirectoryTarget::Target const& t : dt.Targets) { // Add this to the list of depends rules in this directory. - if ((!check_all || !t.ExcludeFromAll) && + if ((!check_all || t.ExcludedFromAllInConfigs.empty()) && (!check_relink || t.GT->NeedRelinkBeforeInstall(lg->GetConfigName()))) { // The target may be from a different directory; use its local gen. @@ -635,17 +631,12 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules( for (const auto& gtarget : lg.GetGeneratorTargets()) { // Don't emit the same rule twice (e.g. two targets with the same // simple name) - int type = gtarget->GetType(); std::string name = gtarget->GetName(); if (!name.empty() && emitted.insert(name).second && // Handle user targets here. Global targets are handled in // the local generator on a per-directory basis. - ((type == cmStateEnums::EXECUTABLE) || - (type == cmStateEnums::STATIC_LIBRARY) || - (type == cmStateEnums::SHARED_LIBRARY) || - (type == cmStateEnums::MODULE_LIBRARY) || - (type == cmStateEnums::OBJECT_LIBRARY) || - (type == cmStateEnums::UTILITY))) { + (gtarget->IsInBuildSystem() && + gtarget->GetType() != cmStateEnums::GLOBAL_TARGET)) { // Add a rule to build the target by name. lg.WriteDivider(ruleFileStream); ruleFileStream << "# Target rules for targets named " << name @@ -709,15 +700,10 @@ void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2( // for each target Generate the rule files for each target. for (const auto& gtarget : lg.GetGeneratorTargets()) { - int type = gtarget->GetType(); std::string name = gtarget->GetName(); if (!name.empty() && - ((type == cmStateEnums::EXECUTABLE) || - (type == cmStateEnums::STATIC_LIBRARY) || - (type == cmStateEnums::SHARED_LIBRARY) || - (type == cmStateEnums::MODULE_LIBRARY) || - (type == cmStateEnums::OBJECT_LIBRARY) || - (type == cmStateEnums::UTILITY))) { + (gtarget->IsInBuildSystem() && + gtarget->GetType() != cmStateEnums::GLOBAL_TARGET)) { std::string makefileName; // Add a rule to build the target by name. localName = lg.GetRelativeTargetDirectory(gtarget.get()); @@ -845,8 +831,7 @@ void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks() for (const auto& gt : lg->GetGeneratorTargets()) { cmLocalGenerator* tlg = gt->GetLocalGenerator(); - if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY || - gt->GetPropertyAsBool("EXCLUDE_FROM_ALL")) { + if (!gt->IsInBuildSystem() || IsExcluded(lg.get(), gt.get())) { continue; } @@ -881,7 +866,7 @@ size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInTarget( if (emitted.insert(target).second) { count = this->ProgressMap[target].Marks.size(); for (cmTargetDepend const& depend : this->GetTargetDirectDepends(target)) { - if (depend->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!depend->IsInBuildSystem()) { continue; } count += this->CountProgressMarksInTarget(depend, emitted); @@ -938,7 +923,7 @@ void cmGlobalUnixMakefileGenerator3::AppendGlobalTargetDepends( for (cmTargetDepend const& i : this->GetTargetDirectDepends(target)) { // Create the target-level dependency. cmGeneratorTarget const* dep = i; - if (dep->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!dep->IsInBuildSystem()) { continue; } cmLocalUnixMakefileGenerator3* lg3 = @@ -986,7 +971,9 @@ void cmGlobalUnixMakefileGenerator3::WriteHelpRule( (type == cmStateEnums::STATIC_LIBRARY) || (type == cmStateEnums::SHARED_LIBRARY) || (type == cmStateEnums::MODULE_LIBRARY) || - (type == cmStateEnums::OBJECT_LIBRARY)) { + (type == cmStateEnums::OBJECT_LIBRARY) || + (type == cmStateEnums::INTERFACE_LIBRARY && + target->IsInBuildSystem())) { project_targets.insert(target->GetName()); } else if (type == cmStateEnums::GLOBAL_TARGET) { globals_targets.insert(target->GetName()); diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 5dac072..3805546 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -138,9 +138,6 @@ cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator( "ProductDir", vc10Express, cmSystemTools::KeyWOW64_32); this->CudaEnabled = false; - this->SystemIsWindowsCE = false; - this->SystemIsWindowsPhone = false; - this->SystemIsWindowsStore = false; this->MSBuildCommandInitialized = false; { std::string envPlatformToolset; @@ -511,18 +508,16 @@ bool cmGlobalVisualStudio10Generator::InitializeSystem(cmMakefile* mf) mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); return false; } - std::string v = this->GetInstalledNsightTegraVersion(); - if (v.empty()) { - mf->IssueMessage(MessageType::FATAL_ERROR, - "CMAKE_SYSTEM_NAME is 'Android' but " - "'NVIDIA Nsight Tegra Visual Studio Edition' " - "is not installed."); - return false; + if (mf->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM") == "Tegra-Android") { + if (!this->InitializeTegraAndroid(mf)) { + return false; + } + } else { + this->SystemIsAndroid = true; + if (!this->InitializeAndroid(mf)) { + return false; + } } - this->DefaultPlatformName = "Tegra-Android"; - this->DefaultPlatformToolset = "Default"; - this->NsightTegraVersion = v; - mf->AddDefinition("CMAKE_VS_NsightTegra_VERSION", v); } return true; @@ -564,6 +559,31 @@ bool cmGlobalVisualStudio10Generator::InitializeWindowsStore(cmMakefile* mf) return false; } +bool cmGlobalVisualStudio10Generator::InitializeTegraAndroid(cmMakefile* mf) +{ + std::string v = this->GetInstalledNsightTegraVersion(); + if (v.empty()) { + mf->IssueMessage(MessageType::FATAL_ERROR, + "CMAKE_SYSTEM_NAME is 'Android' but " + "'NVIDIA Nsight Tegra Visual Studio Edition' " + "is not installed."); + return false; + } + this->DefaultPlatformName = "Tegra-Android"; + this->DefaultPlatformToolset = "Default"; + this->NsightTegraVersion = v; + mf->AddDefinition("CMAKE_VS_NsightTegra_VERSION", v); + return true; +} + +bool cmGlobalVisualStudio10Generator::InitializeAndroid(cmMakefile* mf) +{ + std::ostringstream e; + e << this->GetName() << " does not support Android."; + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return false; +} + bool cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset( std::string& toolset) const { @@ -598,6 +618,28 @@ void cmGlobalVisualStudio10Generator::Generate() { this->LongestSource = LongestSourcePath(); this->cmGlobalVisualStudio8Generator::Generate(); + if (!this->AndroidExecutableWarnings.empty() && + !this->CMakeInstance->GetIsInTryCompile()) { + std::ostringstream e; + /* clang-format off */ + e << + "You are using Visual Studio tools for Android, which does not support " + "standalone executables. However, the following executable targets do " + "not have the ANDROID_GUI property set, and thus will not be built as " + "expected. They will be built as shared libraries with executable " + "filenames:\n" + " "; + /* clang-format on */ + bool first = true; + for (auto const& name : this->AndroidExecutableWarnings) { + if (!first) { + e << ", "; + } + first = false; + e << name; + } + this->CMakeInstance->IssueMessage(MessageType::WARNING, e.str()); + } if (this->LongestSource.Length > 0) { cmLocalGenerator* lg = this->LongestSource.Target->GetLocalGenerator(); std::ostringstream e; @@ -664,8 +706,14 @@ std::string const& cmGlobalVisualStudio10Generator::GetPlatformToolsetString() if (!this->GeneratorToolset.empty()) { return this->GeneratorToolset; } - if (!this->DefaultPlatformToolset.empty()) { - return this->DefaultPlatformToolset; + if (this->SystemIsAndroid) { + if (!this->DefaultAndroidToolset.empty()) { + return this->DefaultAndroidToolset; + } + } else { + if (!this->DefaultPlatformToolset.empty()) { + return this->DefaultPlatformToolset; + } } static std::string const empty; return empty; @@ -879,7 +927,10 @@ bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf) epg.Attribute("Label", "Globals"); cmXMLElement(epg, "ProjectGuid") .Content("{F3FC6D86-508D-3FB1-96D2-995F08B142EC}"); - cmXMLElement(epg, "Keyword").Content("Win32Proj"); + cmXMLElement(epg, "Keyword") + .Content(mf->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android" + ? "Android" + : "Win32Proj"); cmXMLElement(epg, "Platform").Content(this->GetPlatformName()); if (this->GetSystemName() == "WindowsPhone") { cmXMLElement(epg, "ApplicationType").Content("Windows Phone"); @@ -889,15 +940,21 @@ bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf) cmXMLElement(epg, "ApplicationType").Content("Windows Store"); cmXMLElement(epg, "ApplicationTypeRevision") .Content(this->GetApplicationTypeRevision()); + } else if (this->GetSystemName() == "Android") { + cmXMLElement(epg, "ApplicationType").Content("Android"); + cmXMLElement(epg, "ApplicationTypeRevision") + .Content(this->GetApplicationTypeRevision()); } if (!this->WindowsTargetPlatformVersion.empty()) { cmXMLElement(epg, "WindowsTargetPlatformVersion") .Content(this->WindowsTargetPlatformVersion); } - if (this->GetPlatformName() == "ARM64") { - cmXMLElement(epg, "WindowsSDKDesktopARM64Support").Content("true"); - } else if (this->GetPlatformName() == "ARM") { - cmXMLElement(epg, "WindowsSDKDesktopARMSupport").Content("true"); + if (this->GetSystemName() != "Android") { + if (this->GetPlatformName() == "ARM64") { + cmXMLElement(epg, "WindowsSDKDesktopARM64Support").Content("true"); + } else if (this->GetPlatformName() == "ARM") { + cmXMLElement(epg, "WindowsSDKDesktopARMSupport").Content("true"); + } } } cmXMLElement(eprj, "Import") @@ -1209,6 +1266,10 @@ std::string cmGlobalVisualStudio10Generator::GetInstalledNsightTegraVersion() std::string cmGlobalVisualStudio10Generator::GetApplicationTypeRevision() const { + if (this->GetSystemName() == "Android") { + return this->GetAndroidApplicationTypeRevision(); + } + // Return the first two '.'-separated components of the Windows version. std::string::size_type end1 = this->SystemVersion.find('.'); std::string::size_type end2 = diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index b8c18b4..0c53537 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -4,6 +4,7 @@ #define cmGlobalVisualStudio10Generator_h #include <memory> +#include <set> #include "cmGlobalVisualStudio8Generator.h" #include "cmVisualStudio10ToolsetOptions.h" @@ -43,6 +44,11 @@ public: void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*, bool optional) override; + void AddAndroidExecutableWarning(const std::string& name) + { + this->AndroidExecutableWarnings.insert(name); + } + bool IsCudaEnabled() const { return this->CudaEnabled; } /** Generating for Nsight Tegra VS plugin? */ @@ -100,6 +106,9 @@ public: /** Return true if building for WindowsStore */ bool TargetsWindowsStore() const { return this->SystemIsWindowsStore; } + /** Return true if building for Android */ + bool TargetsAndroid() const { return this->SystemIsAndroid; } + const char* GetCMakeCFGIntDir() const override { return "$(Configuration)"; } bool Find64BitTools(cmMakefile* mf); @@ -128,6 +137,8 @@ public: /** Return the first two components of CMAKE_SYSTEM_VERSION. */ std::string GetApplicationTypeRevision() const; + virtual const char* GetAndroidApplicationTypeRevision() const { return ""; } + cmIDEFlagTable const* GetClFlagTable() const; cmIDEFlagTable const* GetCSharpFlagTable() const; cmIDEFlagTable const* GetRcFlagTable() const; @@ -148,6 +159,8 @@ protected: virtual bool InitializeWindowsCE(cmMakefile* mf); virtual bool InitializeWindowsPhone(cmMakefile* mf); virtual bool InitializeWindowsStore(cmMakefile* mf); + virtual bool InitializeTegraAndroid(cmMakefile* mf); + virtual bool InitializeAndroid(cmMakefile* mf); virtual bool ProcessGeneratorToolsetField(std::string const& key, std::string const& value); @@ -171,6 +184,7 @@ protected: std::string GeneratorToolsetCudaCustomDir; std::string DefaultPlatformToolset; std::string DefaultPlatformToolsetHostArchitecture; + std::string DefaultAndroidToolset; std::string WindowsTargetPlatformVersion; std::string SystemName; std::string SystemVersion; @@ -185,9 +199,10 @@ protected: std::string DefaultNasmFlagTableName; std::string DefaultRCFlagTableName; bool SupportsUnityBuilds = false; - bool SystemIsWindowsCE; - bool SystemIsWindowsPhone; - bool SystemIsWindowsStore; + bool SystemIsWindowsCE = false; + bool SystemIsWindowsPhone = false; + bool SystemIsWindowsStore = false; + bool SystemIsAndroid = false; private: class Factory; @@ -211,6 +226,7 @@ private: std::string MSBuildCommand; bool MSBuildCommandInitialized; cmVisualStudio10ToolsetOptions ToolsetOptions; + std::set<std::string> AndroidExecutableWarnings; virtual std::string FindMSBuildCommand(); std::string FindDevEnvCommand() override; std::string GetVSMakeProgram() override { return this->GetMSBuildCommand(); } diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx index f549b6a..451d448 100644 --- a/Source/cmGlobalVisualStudio14Generator.cxx +++ b/Source/cmGlobalVisualStudio14Generator.cxx @@ -109,6 +109,7 @@ cmGlobalVisualStudio14Generator::cmGlobalVisualStudio14Generator( "ProductDir", vc14Express, cmSystemTools::KeyWOW64_32); this->DefaultPlatformToolset = "v140"; + this->DefaultAndroidToolset = "Clang_3_8"; this->DefaultCLFlagTableName = "v140"; this->DefaultCSharpFlagTableName = "v140"; this->DefaultLibFlagTableName = "v14"; @@ -159,6 +160,11 @@ bool cmGlobalVisualStudio14Generator::InitializeWindowsStore(cmMakefile* mf) return true; } +bool cmGlobalVisualStudio14Generator::InitializeAndroid(cmMakefile*) +{ + return true; +} + bool cmGlobalVisualStudio14Generator::SelectWindows10SDK(cmMakefile* mf, bool required) { diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h index ccc2917..39353f2 100644 --- a/Source/cmGlobalVisualStudio14Generator.h +++ b/Source/cmGlobalVisualStudio14Generator.h @@ -23,12 +23,18 @@ public: bool MatchesGeneratorName(const std::string& name) const override; + const char* GetAndroidApplicationTypeRevision() const override + { + return "2.0"; + } + protected: cmGlobalVisualStudio14Generator(cmake* cm, const std::string& name, std::string const& platformInGeneratorName); bool InitializeWindows(cmMakefile* mf) override; bool InitializeWindowsStore(cmMakefile* mf) override; + bool InitializeAndroid(cmMakefile* mf) override; bool SelectWindowsStoreToolset(std::string& toolset) const override; // These aren't virtual because we need to check if the selected version diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index 7ada325..0083c40 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -19,8 +19,8 @@ void cmGlobalVisualStudio71Generator::WriteSLNFile( std::ostream& fout, cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators) { - std::vector<std::string> configs; - root->GetMakefile()->GetConfigurations(configs); + std::vector<std::string> configs = + root->GetMakefile()->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig); // Write out the header for a SLN file this->WriteSLNHeader(fout); diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 428c748..f8b438a 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -339,7 +339,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations( // loop over again and write out configurations for each target // in the solution for (cmGeneratorTarget const* target : projectTargets) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!target->IsInBuildSystem()) { continue; } cmProp expath = target->GetProperty("EXTERNAL_MSPROJECT"); @@ -369,7 +369,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( std::string rootBinaryDir = root->GetCurrentBinaryDirectory(); for (cmGeneratorTarget const* target : projectTargets) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!target->IsInBuildSystem()) { continue; } bool written = false; @@ -436,7 +436,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetDepends( std::ostream& fout, OrderedTargetDependSet const& projectTargets) { for (cmGeneratorTarget const* target : projectTargets) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!target->IsInBuildSystem()) { continue; } cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); @@ -568,8 +568,9 @@ void cmGlobalVisualStudio7Generator::WriteSLNFooter(std::ostream& fout) std::string cmGlobalVisualStudio7Generator::WriteUtilityDepend( cmGeneratorTarget const* target) { - std::vector<std::string> configs; - target->Target->GetMakefile()->GetConfigurations(configs); + std::vector<std::string> configs = + target->Target->GetMakefile()->GetGeneratorConfigs( + cmMakefile::ExcludeEmptyConfig); std::string pname = cmStrCat(target->GetName(), "_UTILITY"); std::string fname = cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/', @@ -693,9 +694,7 @@ std::set<std::string> cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild( } // inspect EXCLUDE_FROM_DEFAULT_BUILD[_<CONFIG>] properties for (std::string const& i : configs) { - const char* propertyValue = - target->GetFeature("EXCLUDE_FROM_DEFAULT_BUILD", i); - if (cmIsOff(propertyValue)) { + if (cmIsOff(target->GetFeature("EXCLUDE_FROM_DEFAULT_BUILD", i))) { activeConfigs.insert(i); } } diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index 29ca154..fcdfc50 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -325,7 +325,7 @@ void cmGlobalVisualStudio8Generator::WriteProjectDepends( TargetDependSet const& unordered = this->GetTargetDirectDepends(gt); OrderedTargetDependSet depends(unordered, std::string()); for (cmTargetDepend const& i : depends) { - if (i->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!i->IsInBuildSystem()) { continue; } std::string guid = this->GetGUID(i->GetName()); @@ -341,7 +341,7 @@ bool cmGlobalVisualStudio8Generator::NeedLinkLibraryDependencies( if (cmGeneratorTarget* depTarget = target->GetLocalGenerator()->FindGeneratorTargetToUse( ui.Value.first)) { - if (depTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY && + if (depTarget->IsInBuildSystem() && depTarget->GetProperty("EXTERNAL_MSPROJECT")) { // This utility dependency names an external .vcproj target. // We use LinkLibraryDependencies="true" to link to it without diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index c688da2..001d876 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -368,7 +368,7 @@ cmGlobalVisualStudioGenerator::GetTargetLinkClosure(cmGeneratorTarget* target) void cmGlobalVisualStudioGenerator::FollowLinkDepends( const cmGeneratorTarget* target, std::set<const cmGeneratorTarget*>& linked) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!target->IsInBuildSystem()) { return; } if (linked.insert(target).second && @@ -509,7 +509,7 @@ std::string cmGlobalVisualStudioGenerator::GetStartupProjectName( cmLocalGenerator const* root) const { cmProp n = root->GetMakefile()->GetProperty("VS_STARTUP_PROJECT"); - if (n && !n->empty()) { + if (cmNonempty(n)) { std::string startup = *n; if (this->FindTarget(startup)) { return startup; @@ -810,7 +810,7 @@ bool cmGlobalVisualStudioGenerator::TargetIsFortranOnly( // a target with none of its own sources, e.g. when also using // object libraries. cmProp linkLang = gt->GetProperty("LINKER_LANGUAGE"); - if (linkLang && !linkLang->empty()) { + if (cmNonempty(linkLang)) { languages.insert(*linkLang); } diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index 605dc8b..e2e045c 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -100,6 +100,24 @@ static const char* VSVersionToToolset( return ""; } +static const char* VSVersionToAndroidToolset( + cmGlobalVisualStudioGenerator::VSVersion v) +{ + switch (v) { + case cmGlobalVisualStudioGenerator::VS9: + case cmGlobalVisualStudioGenerator::VS10: + case cmGlobalVisualStudioGenerator::VS11: + case cmGlobalVisualStudioGenerator::VS12: + return ""; + case cmGlobalVisualStudioGenerator::VS14: + return "Clang_3_8"; + case cmGlobalVisualStudioGenerator::VS15: + case cmGlobalVisualStudioGenerator::VS16: + return "Clang_5_0"; + } + return ""; +} + static const char vs15generatorName[] = "Visual Studio 15 2017"; // Map generator name without year to name with year. @@ -284,6 +302,7 @@ cmGlobalVisualStudioVersionedGenerator::cmGlobalVisualStudioVersionedGenerator( this->Version = version; this->ExpressEdition = false; this->DefaultPlatformToolset = VSVersionToToolset(this->Version); + this->DefaultAndroidToolset = VSVersionToAndroidToolset(this->Version); this->DefaultCLFlagTableName = VSVersionToToolset(this->Version); this->DefaultCSharpFlagTableName = VSVersionToToolset(this->Version); this->DefaultLinkFlagTableName = VSVersionToToolset(this->Version); @@ -408,6 +427,25 @@ bool cmGlobalVisualStudioVersionedGenerator::IsStdOutEncodingSupported() const vsInstanceVersion > vsInstanceVersion16_7_P2); } +const char* +cmGlobalVisualStudioVersionedGenerator::GetAndroidApplicationTypeRevision() + const +{ + switch (this->Version) { + case cmGlobalVisualStudioGenerator::VS9: + case cmGlobalVisualStudioGenerator::VS10: + case cmGlobalVisualStudioGenerator::VS11: + case cmGlobalVisualStudioGenerator::VS12: + return ""; + case cmGlobalVisualStudioGenerator::VS14: + return "2.0"; + case cmGlobalVisualStudioGenerator::VS15: + case cmGlobalVisualStudioGenerator::VS16: + return "3.0"; + } + return ""; +} + std::string cmGlobalVisualStudioVersionedGenerator::GetAuxiliaryToolset() const { const char* version = this->GetPlatformToolsetVersion(); diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h index cbd3ba7..d5b8337 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.h +++ b/Source/cmGlobalVisualStudioVersionedGenerator.h @@ -36,6 +36,8 @@ public: bool IsStdOutEncodingSupported() const override; + const char* GetAndroidApplicationTypeRevision() const override; + protected: cmGlobalVisualStudioVersionedGenerator( VSVersion version, cmake* cm, const std::string& name, diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index b28395a..793f6f7 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -173,6 +173,7 @@ cmGlobalXCodeGenerator::cmGlobalXCodeGenerator( this->RootObject = nullptr; this->MainGroupChildren = nullptr; + this->FrameworkGroup = nullptr; this->CurrentMakefile = nullptr; this->CurrentLocalGenerator = nullptr; this->XcodeBuildCommandInitialized = false; @@ -476,6 +477,9 @@ void cmGlobalXCodeGenerator::Generate() } } + // cache the enabled languages for source file type queries + this->GetEnabledLanguages(this->EnabledLangs); + this->SetGenerationRoot(root); // now create the project this->OutputXCodeProject(root, keyVal.second); @@ -673,6 +677,7 @@ void cmGlobalXCodeGenerator::ClearXCodeObjects() this->GroupNameMap.clear(); this->TargetGroup.clear(); this->FileRefs.clear(); + this->ExternalLibRefs.clear(); } void cmGlobalXCodeGenerator::addObject(std::unique_ptr<cmXCodeObject> obj) @@ -741,7 +746,7 @@ std::string GetGroupMapKeyFromPath(cmGeneratorTarget* target, return key; } -cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath( +cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeBuildFileFromPath( const std::string& fullpath, cmGeneratorTarget* target, const std::string& lang, cmSourceFile* sf) { @@ -827,6 +832,14 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( default: break; } + + // explicitly add the explicit language flag before any other flag + // this way backwards compatibility with user flags is maintained + if (sf->GetProperty("LANGUAGE")) { + this->CurrentLocalGenerator->AppendFeatureOptions(flags, lang, + "EXPLICIT_LANGUAGE"); + } + const std::string COMPILE_FLAGS("COMPILE_FLAGS"); if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) { lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS)); @@ -869,7 +882,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( lg->AppendFlags(flags, lg->GetIncludeFlags(includes, gtgt, lang, true)); cmXCodeObject* buildFile = - this->CreateXCodeSourceFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf); + this->CreateXCodeBuildFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf); cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); settings->AddAttributeIfNotEmpty("COMPILER_FLAGS", @@ -922,14 +935,40 @@ void cmGlobalXCodeGenerator::AddXCodeProjBuildRule( } } -std::string GetSourcecodeValueFromFileExtension(const std::string& _ext, - const std::string& lang, - bool& keepLastKnownFileType) +bool IsLibraryExtension(const std::string& fileExt) +{ + return (fileExt == ".framework" || fileExt == ".a" || fileExt == ".o" || + fileExt == ".dylib" || fileExt == ".tbd"); +} +bool IsLibraryType(const std::string& fileType) +{ + return (fileType == "wrapper.framework" || fileType == "archive.ar" || + fileType == "compiled.mach-o.objfile" || + fileType == "compiled.mach-o.dylib" || + fileType == "sourcecode.text-based-dylib-definition"); +} + +std::string GetDirectoryValueFromFileExtension(const std::string& dirExt) +{ + std::string ext = cmSystemTools::LowerCase(dirExt); + if (ext == "framework") { + return "wrapper.framework"; + } + if (ext == "xcassets") { + return "folder.assetcatalog"; + } + return "folder"; +} + +std::string GetSourcecodeValueFromFileExtension( + const std::string& _ext, const std::string& lang, + bool& keepLastKnownFileType, const std::vector<std::string>& enabled_langs) { std::string ext = cmSystemTools::LowerCase(_ext); std::string sourcecode = "sourcecode"; if (ext == "o") { + keepLastKnownFileType = true; sourcecode = "compiled.mach-o.objfile"; } else if (ext == "xctest") { sourcecode = "wrapper.cfbundle"; @@ -939,9 +978,9 @@ std::string GetSourcecodeValueFromFileExtension(const std::string& _ext, } else if (ext == "storyboard") { keepLastKnownFileType = true; sourcecode = "file.storyboard"; - } else if (ext == "mm") { + } else if (ext == "mm" && !cm::contains(enabled_langs, "OBJCXX")) { sourcecode += ".cpp.objcpp"; - } else if (ext == "m") { + } else if (ext == "m" && !cm::contains(enabled_langs, "OBJC")) { sourcecode += ".c.objc"; } else if (ext == "swift") { sourcecode += ".swift"; @@ -973,6 +1012,14 @@ std::string GetSourcecodeValueFromFileExtension(const std::string& _ext, sourcecode += ".metal"; } else if (ext == "mig") { sourcecode += ".mig"; + } else if (ext == "tbd") { + sourcecode += ".text-based-dylib-definition"; + } else if (ext == "a") { + keepLastKnownFileType = true; + sourcecode = "archive.ar"; + } else if (ext == "dylib") { + keepLastKnownFileType = true; + sourcecode = "compiled.mach-o.dylib"; } // else // { @@ -989,20 +1036,6 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( const std::string& fullpath, cmGeneratorTarget* target, const std::string& lang, cmSourceFile* sf) { - std::string key = GetGroupMapKeyFromPath(target, fullpath); - cmXCodeObject* fileRef = this->FileRefs[key]; - if (!fileRef) { - fileRef = this->CreateObject(cmXCodeObject::PBXFileReference); - fileRef->SetComment(fullpath); - this->FileRefs[key] = fileRef; - } - cmXCodeObject* group = this->GroupMap[key]; - cmXCodeObject* children = group->GetObject("children"); - if (!children->HasObject(fileRef)) { - children->AddObject(fileRef); - } - fileRef->AddAttribute("fileEncoding", this->CreateString("4")); - bool useLastKnownFileType = false; std::string fileType; if (sf) { @@ -1013,38 +1046,70 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( fileType = *l; } } + // Make a copy so that we can override it later + std::string path = fullpath; + // Compute the extension without leading '.'. + std::string ext = cmSystemTools::GetFilenameLastExtension(path); + if (!ext.empty()) { + ext = ext.substr(1); + } if (fileType.empty()) { - // Compute the extension without leading '.'. - std::string ext = cmSystemTools::GetFilenameLastExtension(fullpath); - if (!ext.empty()) { - ext = ext.substr(1); + // If file has no extension it's either a raw executable or might + // be a direct reference to binary within a framework (bad practice!) + // so this is where we change the path to the point to framework + // directory. + if (ext.empty()) { + auto parentDir = cmSystemTools::GetParentDirectory(path); + auto parentExt = cmSystemTools::GetFilenameLastExtension(parentDir); + if (parentExt == ".framework") { + path = parentDir; + ext = parentExt.substr(1); + } } - // If fullpath references a directory, then we need to specify // lastKnownFileType as folder in order for Xcode to be able to // open the contents of the folder. // (Xcode 4.6 does not like explicitFileType=folder). - if (cmSystemTools::FileIsDirectory(fullpath)) { - fileType = (ext == "xcassets" ? "folder.assetcatalog" : "folder"); + if (cmSystemTools::FileIsDirectory(path)) { + fileType = GetDirectoryValueFromFileExtension(ext); useLastKnownFileType = true; } else { - fileType = - GetSourcecodeValueFromFileExtension(ext, lang, useLastKnownFileType); + fileType = GetSourcecodeValueFromFileExtension( + ext, lang, useLastKnownFileType, this->EnabledLangs); } } + std::string key = GetGroupMapKeyFromPath(target, path); + cmXCodeObject* fileRef = this->FileRefs[key]; + if (!fileRef) { + fileRef = this->CreateObject(cmXCodeObject::PBXFileReference); + fileRef->SetComment(path); + this->FileRefs[key] = fileRef; + } + fileRef->AddAttribute("fileEncoding", this->CreateString("4")); fileRef->AddAttribute(useLastKnownFileType ? "lastKnownFileType" : "explicitFileType", this->CreateString(fileType)); - // Store the file path relative to the top of the source tree. - std::string path = this->RelativeToSource(fullpath); + if (!IsLibraryType(fileType)) { + path = this->RelativeToSource(path); + } std::string name = cmSystemTools::GetFilenameName(path); const char* sourceTree = cmSystemTools::FileIsFullPath(path) ? "<absolute>" : "SOURCE_ROOT"; fileRef->AddAttribute("name", this->CreateString(name)); fileRef->AddAttribute("path", this->CreateString(path)); fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree)); + + cmXCodeObject* group = this->GroupMap[key]; + if (!group && IsLibraryType(fileType)) { + group = this->FrameworkGroup; + this->GroupMap[key] = group; + } + cmXCodeObject* children = group->GetObject("children"); + if (!children->HasObject(fileRef)) { + children->AddObject(fileRef); + } return fileRef; } @@ -1077,11 +1142,8 @@ void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen) this->CurrentMakefile = gen->GetMakefile(); // Select the current set of configuration types. - this->CurrentConfigurationTypes.clear(); - this->CurrentMakefile->GetConfigurations(this->CurrentConfigurationTypes); - if (this->CurrentConfigurationTypes.empty()) { - this->CurrentConfigurationTypes.emplace_back(); - } + this->CurrentConfigurationTypes = + this->CurrentMakefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); } struct cmSourceFilePathCompare @@ -1137,11 +1199,12 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( return true; } - if (gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!gtgt->IsInBuildSystem()) { return true; } if (gtgt->GetType() == cmStateEnums::UTILITY || + gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY || gtgt->GetType() == cmStateEnums::GLOBAL_TARGET) { cmXCodeObject* t = this->CreateUtilityTarget(gtgt); if (!t) { @@ -1152,23 +1215,24 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( } // organize the sources - std::vector<cmSourceFile*> classes; - if (!gtgt->GetConfigCommonSourceFiles(classes)) { + std::vector<cmSourceFile*> commonSourceFiles; + if (!gtgt->GetConfigCommonSourceFiles(commonSourceFiles)) { return false; } // Add CMakeLists.txt file for user convenience. - this->AddXCodeProjBuildRule(gtgt, classes); + this->AddXCodeProjBuildRule(gtgt, commonSourceFiles); // Add the Info.plist we are about to generate for an App Bundle. if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) { std::string plist = this->ComputeInfoPListLocation(gtgt); cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource( plist, true, cmSourceFileLocationKind::Known); - classes.push_back(sf); + commonSourceFiles.push_back(sf); } - std::sort(classes.begin(), classes.end(), cmSourceFilePathCompare()); + std::sort(commonSourceFiles.begin(), commonSourceFiles.end(), + cmSourceFilePathCompare()); gtgt->ComputeObjectMapping(); @@ -1176,16 +1240,19 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( std::vector<cmXCodeObject*> headerFiles; std::vector<cmXCodeObject*> resourceFiles; std::vector<cmXCodeObject*> sourceFiles; - for (auto sourceFile : classes) { + for (auto sourceFile : commonSourceFiles) { cmXCodeObject* xsf = this->CreateXCodeSourceFile( this->CurrentLocalGenerator, sourceFile, gtgt); cmXCodeObject* fr = xsf->GetObject("fileRef"); cmXCodeObject* filetype = fr->GetObject()->GetObject("explicitFileType"); + if (!filetype) { + filetype = fr->GetObject()->GetObject("lastKnownFileType"); + } cmGeneratorTarget::SourceFileFlags tsFlags = gtgt->GetTargetSourceFileFlags(sourceFile); - if (filetype && filetype->GetString() == "compiled.mach-o.objfile") { + if (filetype && IsLibraryType(filetype->GetString())) { if (sourceFile->GetObjectLibrary().empty()) { externalObjFiles.push_back(xsf); } @@ -1275,7 +1342,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( using mapOfVectorOfSourceFiles = std::map<std::string, std::vector<cmSourceFile*>>; mapOfVectorOfSourceFiles bundleFiles; - for (auto sourceFile : classes) { + for (auto sourceFile : commonSourceFiles) { cmGeneratorTarget::SourceFileFlags tsFlags = gtgt->GetTargetSourceFileFlags(sourceFile); if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeMacContent) { @@ -1323,7 +1390,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( using mapOfVectorOfSourceFiles = std::map<std::string, std::vector<cmSourceFile*>>; mapOfVectorOfSourceFiles bundleFiles; - for (auto sourceFile : classes) { + for (auto sourceFile : commonSourceFiles) { cmGeneratorTarget::SourceFileFlags tsFlags = gtgt->GetTargetSourceFileFlags(sourceFile); if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeDeepResource) { @@ -1353,22 +1420,20 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( } } - // create framework build phase + // always create framework build phase cmXCodeObject* frameworkBuildPhase = nullptr; - if (!externalObjFiles.empty()) { - frameworkBuildPhase = - this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase); - frameworkBuildPhase->SetComment("Frameworks"); - frameworkBuildPhase->AddAttribute("buildActionMask", - this->CreateString("2147483647")); - buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); - frameworkBuildPhase->AddAttribute("files", buildFiles); - for (auto& externalObjFile : externalObjFiles) { - buildFiles->AddObject(externalObjFile); - } - frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", - this->CreateString("0")); - } + frameworkBuildPhase = + this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase); + frameworkBuildPhase->SetComment("Frameworks"); + frameworkBuildPhase->AddAttribute("buildActionMask", + this->CreateString("2147483647")); + buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); + frameworkBuildPhase->AddAttribute("files", buildFiles); + for (auto& externalObjFile : externalObjFiles) { + buildFiles->AddObject(externalObjFile); + } + frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", + this->CreateString("0")); // create list of build phases and create the Xcode target cmXCodeObject* buildPhases = this->CreateObject(cmXCodeObject::OBJECT_LIST); @@ -1781,7 +1846,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, cmXCodeObject* buildSettings, const std::string& configName) { - if (gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!gtgt->IsInBuildSystem()) { return; } @@ -2472,7 +2537,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget( this->XCodeObjectMap[gtgt] = target; // Add source files without build rules for editing convenience. - if (gtgt->GetType() == cmStateEnums::UTILITY && + if (gtgt->GetType() != cmStateEnums::GLOBAL_TARGET && gtgt->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { std::vector<cmSourceFile*> sources; if (!gtgt->GetConfigCommonSourceFiles(sources)) { @@ -2614,7 +2679,7 @@ const char* cmGlobalXCodeGenerator::GetTargetProductType( cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeTarget( cmGeneratorTarget* gtgt, cmXCodeObject* buildPhases) { - if (gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!gtgt->IsInBuildSystem()) { return nullptr; } cmXCodeObject* target = this->CreateObject(cmXCodeObject::PBXNativeTarget); @@ -2757,7 +2822,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) cmSystemTools::Error("Error no target on xobject\n"); return; } - if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!gt->IsInBuildSystem()) { return; } @@ -2768,6 +2833,190 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) } } + // Separate libraries into ones that can be linked using "Link Binary With + // Libraries" build phase and the ones that can't. Only targets that build + // Apple bundles (.app, .framework, .bundle) can use this feature and only + // targets that represent actual libraries (static or dynamic, local or + // imported) not objects and not executables will be used. These are + // limitations imposed by CMake use-cases - otherwise a lot of things break. + // The rest will be linked using linker flags (OTHER_LDFLAGS setting in Xcode + // project). + std::map<std::string, std::vector<cmComputeLinkInformation::Item const*>> + configItemMap; + auto addToLinkerArguments = + [&configItemMap](const std::string& configName, + cmComputeLinkInformation::Item const* libItemPtr) { + auto& linkVector = configItemMap[configName]; + if (std::find_if(linkVector.begin(), linkVector.end(), + [libItemPtr](cmComputeLinkInformation::Item const* p) { + return p == libItemPtr; + }) == linkVector.end()) { + linkVector.push_back(libItemPtr); + } + }; + std::vector<cmComputeLinkInformation::Item const*> linkPhaseTargetVector; + std::map<std::string, std::vector<std::string>> targetConfigMap; + using ConfigItemPair = + std::pair<std::string, cmComputeLinkInformation::Item const*>; + std::map<std::string, std::vector<ConfigItemPair>> targetItemMap; + std::map<std::string, std::vector<std::string>> targetProductNameMap; + for (auto const& configName : this->CurrentConfigurationTypes) { + cmComputeLinkInformation* cli = gt->GetLinkInformation(configName); + if (!cli) { + continue; + } + for (auto const& libItem : cli->GetItems()) { + if (gt->IsBundleOnApple() && + (gt->GetType() == cmStateEnums::EXECUTABLE || + gt->GetType() == cmStateEnums::SHARED_LIBRARY || + gt->GetType() == cmStateEnums::MODULE_LIBRARY || + gt->GetType() == cmStateEnums::UNKNOWN_LIBRARY) && + ((libItem.Target && + (libItem.Target->GetType() == cmStateEnums::STATIC_LIBRARY || + libItem.Target->GetType() == cmStateEnums::SHARED_LIBRARY || + libItem.Target->GetType() == cmStateEnums::MODULE_LIBRARY)) || + (!libItem.Target && libItem.IsPath))) { + // Add unique configuration name to target-config map for later + // checks + std::string libName; + if (libItem.Target) { + libName = libItem.Target->GetName(); + } else { + libName = cmSystemTools::GetFilenameName(libItem.Value.Value); + const auto libExt = cmSystemTools::GetFilenameExtension(libName); + if (!IsLibraryExtension(libExt)) { + // Add this library item to a regular linker flag list + addToLinkerArguments(configName, &libItem); + continue; + } + } + auto& configVector = targetConfigMap[libName]; + if (std::find(configVector.begin(), configVector.end(), configName) == + configVector.end()) { + configVector.push_back(configName); + } + // Add a pair of config and item to target-item map + auto& itemVector = targetItemMap[libName]; + itemVector.emplace_back(ConfigItemPair(configName, &libItem)); + // Add product file-name to a lib-product map + auto productName = cmSystemTools::GetFilenameName(libItem.Value.Value); + auto& productVector = targetProductNameMap[libName]; + if (std::find(productVector.begin(), productVector.end(), + productName) == productVector.end()) { + productVector.push_back(productName); + } + } else { + // Add this library item to a regular linker flag list + addToLinkerArguments(configName, &libItem); + } + } + } + + // Go through target library map and separate libraries that are linked + // in all configurations and produce only single product, from the rest. + // Only these will be linked through "Link Binary With Libraries" build + // phase. + for (auto const& targetLibConfigs : targetConfigMap) { + // Add this library to "Link Binary With Libraries" build phase if it's + // linked in all configurations and it has only one product name + auto& itemVector = targetItemMap[targetLibConfigs.first]; + auto& productVector = targetProductNameMap[targetLibConfigs.first]; + if (targetLibConfigs.second == this->CurrentConfigurationTypes && + productVector.size() == 1) { + // Add this library to "Link Binary With Libraries" list + linkPhaseTargetVector.push_back(itemVector[0].second); + } else { + for (auto const& libItem : targetItemMap[targetLibConfigs.first]) { + // Add this library item to a regular linker flag list + addToLinkerArguments(libItem.first, libItem.second); + } + } + } + + // Add libraries to "Link Binary With Libraries" build phase and collect + // their search paths. Xcode does not support per-configuration linking + // in this build phase so we don't have to do this for each configuration + // separately. + std::vector<std::string> linkSearchPaths; + for (auto const& libItem : linkPhaseTargetVector) { + // Add target output directory as a library search path + std::string linkDir; + if (libItem->Target) { + linkDir = cmSystemTools::GetParentDirectory( + libItem->Target->GetLocationForBuild()); + } else { + linkDir = cmSystemTools::GetParentDirectory(libItem->Value.Value); + } + if (std::find(linkSearchPaths.begin(), linkSearchPaths.end(), linkDir) == + linkSearchPaths.end()) { + linkSearchPaths.push_back(linkDir); + } + // Add target dependency + if (libItem->Target && !libItem->Target->IsImported()) { + for (auto const& configName : this->CurrentConfigurationTypes) { + target->AddDependTarget(configName, libItem->Target->GetName()); + } + } + // Get the library target + auto* libTarget = FindXCodeTarget(libItem->Target); + cmXCodeObject* buildFile; + if (!libTarget) { + if (libItem->IsPath) { + // Get or create a direct file ref in the root project + auto it = this->ExternalLibRefs.find(libItem->Value.Value); + if (it == this->ExternalLibRefs.end()) { + buildFile = CreateXCodeBuildFileFromPath(libItem->Value.Value, gt, + "", nullptr); + this->ExternalLibRefs.emplace(libItem->Value.Value, buildFile); + } else { + buildFile = it->second; + } + } else { + // Add this library item back to a regular linker flag list + for (const auto& conf : configItemMap) { + addToLinkerArguments(conf.first, libItem); + } + continue; + } + } else { + // Add the target output file as a build reference for other targets + // to link against + auto* fileRefObject = libTarget->GetObject("productReference"); + if (!fileRefObject) { + // Add this library item back to a regular linker flag list + for (const auto& conf : configItemMap) { + addToLinkerArguments(conf.first, libItem); + } + continue; + } + auto it = FileRefToBuildFileMap.find(fileRefObject); + if (it == FileRefToBuildFileMap.end()) { + buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile); + buildFile->AddAttribute("fileRef", fileRefObject); + FileRefToBuildFileMap[fileRefObject] = buildFile; + } else { + buildFile = it->second; + } + } + // Add this reference to current target + auto* buildPhases = target->GetObject("buildPhases"); + if (!buildPhases) { + continue; + } + auto* frameworkBuildPhase = + buildPhases->GetObject(cmXCodeObject::PBXFrameworksBuildPhase); + if (!frameworkBuildPhase) { + continue; + } + auto* buildFiles = frameworkBuildPhase->GetObject("files"); + if (!buildFiles) { + continue; + } + if (!buildFiles->HasObject(buildFile)) { + buildFiles->AddObject(buildFile); + } + } + // Loop over configuration types and set per-configuration info. for (auto const& configName : this->CurrentConfigurationTypes) { { @@ -2795,21 +3044,20 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) } // Compute the link library and directory information. - cmComputeLinkInformation* pcli = gt->GetLinkInformation(configName); - if (!pcli) { + cmComputeLinkInformation* cli = gt->GetLinkInformation(configName); + if (!cli) { continue; } - cmComputeLinkInformation& cli = *pcli; // Add dependencies directly on library files. - for (auto const& libDep : cli.GetDepends()) { + for (auto const& libDep : cli->GetDepends()) { target->AddDependLibrary(configName, libDep); } // add the library search paths { std::string linkDirs; - for (auto const& libDir : cli.GetDirectories()) { + for (auto const& libDir : cli->GetDirectories()) { if (!libDir.empty() && libDir != "/usr/lib") { // Now add the same one but append // $(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) to it: @@ -2820,15 +3068,22 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) linkDirs += this->XCodeEscapePath(libDir); } } + // Add previously collected paths where to look for libraries + // that were added to "Link Binary With Libraries" + for (auto& linkDir : linkSearchPaths) { + linkDirs += " "; + linkDirs += this->XCodeEscapePath(linkDir); + } this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS", linkDirs.c_str(), configName); } - // now add the link libraries + // now add the left-over link libraries { std::string linkLibs; const char* sep = ""; - for (auto const& libName : cli.GetItems()) { + for (auto const& libItem : configItemMap[configName]) { + auto const& libName = *libItem; linkLibs += sep; sep = " "; if (libName.IsPath) { @@ -2859,13 +3114,9 @@ bool cmGlobalXCodeGenerator::CreateGroups( // end up with (empty anyhow) ZERO_CHECK, install, or test source // groups: // - if (gtgt->GetType() == cmStateEnums::GLOBAL_TARGET) { - continue; - } - if (gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { - continue; - } - if (gtgt->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET) { + if (!gtgt->IsInBuildSystem() || + gtgt->GetType() == cmStateEnums::GLOBAL_TARGET || + gtgt->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET) { continue; } @@ -3009,6 +3260,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( this->ClearXCodeObjects(); this->RootObject = nullptr; this->MainGroupChildren = nullptr; + this->FrameworkGroup = nullptr; cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO")); cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST); @@ -3043,6 +3295,15 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( productGroup->AddAttribute("children", productGroupChildren); this->MainGroupChildren->AddObject(productGroup); + this->FrameworkGroup = this->CreateObject(cmXCodeObject::PBXGroup); + this->FrameworkGroup->AddAttribute("name", this->CreateString("Frameworks")); + this->FrameworkGroup->AddAttribute("sourceTree", + this->CreateString("<group>")); + cmXCodeObject* frameworkGroupChildren = + this->CreateObject(cmXCodeObject::OBJECT_LIST); + this->FrameworkGroup->AddAttribute("children", frameworkGroupChildren); + this->MainGroupChildren->AddObject(this->FrameworkGroup); + this->RootObject = this->CreateObject(cmXCodeObject::PBXProject); this->RootObject->SetComment("Project object"); @@ -3121,7 +3382,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("YES")); // When targeting macOS, use only the host architecture. if (this->SystemName == "Darwin"_s && - (!sysroot || !*sysroot || + (!cmNonempty(sysroot) || cmSystemTools::LowerCase(sysroot).find("macos") != std::string::npos)) { buildSettings->AddAttribute("ARCHS", @@ -3131,7 +3392,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( // Tell Xcode to use ARCHS (ONLY_ACTIVE_ARCH defaults to NO). buildSettings->AddAttribute("ARCHS", this->CreateString(archs)); } - if (deploymentTarget && *deploymentTarget) { + if (cmNonempty(deploymentTarget)) { buildSettings->AddAttribute(GetDeploymentPlatform(root->GetMakefile()), this->CreateString(deploymentTarget)); } diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index e2d1b3a..7018de7 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -28,7 +28,7 @@ struct cmDocumentationEntry; /** \class cmGlobalXCodeGenerator * \brief Write a Unix makefiles. * - * cmGlobalXCodeGenerator manages UNIX build process for a tree + * cmGlobalXCodeGenerator manages Xcode build process for a tree */ class cmGlobalXCodeGenerator : public cmGlobalGenerator { @@ -204,10 +204,10 @@ private: cmGeneratorTarget* target, const std::string& lang, cmSourceFile* sf); - cmXCodeObject* CreateXCodeSourceFileFromPath(const std::string& fullpath, - cmGeneratorTarget* target, - const std::string& lang, - cmSourceFile* sf); + cmXCodeObject* CreateXCodeBuildFileFromPath(const std::string& fullpath, + cmGeneratorTarget* target, + const std::string& lang, + cmSourceFile* sf); cmXCodeObject* CreateXCodeFileReference(cmSourceFile* sf, cmGeneratorTarget* target); cmXCodeObject* CreateXCodeSourceFile(cmLocalGenerator* gen, cmSourceFile* sf, @@ -282,6 +282,7 @@ private: std::string PostBuildMakeTarget(std::string const& tName, std::string const& configName); cmXCodeObject* MainGroupChildren; + cmXCodeObject* FrameworkGroup; cmMakefile* CurrentMakefile; cmLocalGenerator* CurrentLocalGenerator; std::vector<std::string> CurrentConfigurationTypes; @@ -295,13 +296,16 @@ private: std::map<std::string, cmXCodeObject*> GroupNameMap; std::map<std::string, cmXCodeObject*> TargetGroup; std::map<std::string, cmXCodeObject*> FileRefs; + std::map<std::string, cmXCodeObject*> ExternalLibRefs; std::map<cmGeneratorTarget const*, cmXCodeObject*> XCodeObjectMap; + std::map<cmXCodeObject*, cmXCodeObject*> FileRefToBuildFileMap; std::vector<std::string> Architectures; std::string ObjectDirArchDefault; std::string ObjectDirArch; std::string SystemName; std::string GeneratorToolset; std::map<cmGeneratorTarget const*, size_t> TargetOrderIndex; + std::vector<std::string> EnabledLangs; }; #endif diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx index c23156d..8a7728e 100644 --- a/Source/cmGraphVizWriter.cxx +++ b/Source/cmGraphVizWriter.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGraphVizWriter.h" +#include <algorithm> #include <cctype> #include <iostream> #include <memory> @@ -125,14 +126,6 @@ cmGraphVizWriter::cmGraphVizWriter(std::string const& fileName, cmGraphVizWriter::~cmGraphVizWriter() { this->WriteFooter(this->GlobalFileStream); - - for (auto& fileStream : this->PerTargetFileStreams) { - this->WriteFooter(*fileStream.second); - } - - for (auto& fileStream : this->TargetDependersFileStreams) { - this->WriteFooter(*fileStream.second); - } } void cmGraphVizWriter::VisitGraph(std::string const&) @@ -151,20 +144,10 @@ void cmGraphVizWriter::OnItem(cmLinkItem const& item) ++NextNodeId; this->WriteNode(this->GlobalFileStream, item); - - if (this->GeneratePerTarget) { - this->CreateTargetFile(this->PerTargetFileStreams, item); - } - - if (this->GenerateDependers) { - this->CreateTargetFile(this->TargetDependersFileStreams, item, - ".dependers"); - } } -void cmGraphVizWriter::CreateTargetFile(FileStreamMap& fileStreamMap, - cmLinkItem const& item, - std::string const& fileNameSuffix) +std::unique_ptr<cmGeneratedFileStream> cmGraphVizWriter::CreateTargetFile( + cmLinkItem const& item, std::string const& fileNameSuffix) { auto const pathSafeItemName = PathSafeString(item.AsStr()); auto const perTargetFileName = @@ -175,7 +158,7 @@ void cmGraphVizWriter::CreateTargetFile(FileStreamMap& fileStreamMap, this->WriteHeader(*perTargetFileStream, item.AsStr()); this->WriteNode(*perTargetFileStream, item); - fileStreamMap.emplace(item.AsStr(), std::move(perTargetFileStream)); + return perTargetFileStream; } void cmGraphVizWriter::OnDirectLink(cmLinkItem const& depender, @@ -260,7 +243,7 @@ void cmGraphVizWriter::ReadSettings( do { \ const char* value = mf.GetDefinition(cmakeDefinition); \ if (value) { \ - (var) = mf.IsOn(cmakeDefinition); \ + (var) = cmIsOn(value); \ } \ } while (false) @@ -323,13 +306,12 @@ void cmGraphVizWriter::Write() } if (this->GeneratePerTarget) { - WritePerTargetConnections<DependeesDir>(PerTargetConnections, - PerTargetFileStreams); + WritePerTargetConnections<DependeesDir>(PerTargetConnections); } if (this->GenerateDependers) { WritePerTargetConnections<DependersDir>(TargetDependersConnections, - TargetDependersFileStreams); + ".dependers"); } } @@ -368,7 +350,7 @@ void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap, template <typename DirFunc> void cmGraphVizWriter::WritePerTargetConnections( - const ConnectionsMap& connections, const FileStreamMap& streams) + const ConnectionsMap& connections, const std::string& fileNameSuffix) { // the per target connections must be extended by indirect dependencies ConnectionsMap extendedConnections; @@ -387,7 +369,9 @@ void cmGraphVizWriter::WritePerTargetConnections( } const Connections& cons = conPerTarget.second; - auto fileStream = streams.at(rootItem.AsStr()).get(); + + std::unique_ptr<cmGeneratedFileStream> fileStream = + this->CreateTargetFile(rootItem, fileNameSuffix); for (const Connection& con : cons) { const cmLinkItem& src = DirFunc::src(con); @@ -395,6 +379,8 @@ void cmGraphVizWriter::WritePerTargetConnections( this->WriteNode(*fileStream, con.dst); this->WriteConnection(*fileStream, src, dst, con.scopeType); } + + this->WriteFooter(*fileStream); } } @@ -567,16 +553,23 @@ bool cmGraphVizWriter::TargetTypeEnabled( std::string cmGraphVizWriter::ItemNameWithAliases( std::string const& itemName) const { - auto nameWithAliases = itemName; - + std::vector<std::string> items; for (auto const& lg : this->GlobalGenerator->GetLocalGenerators()) { for (auto const& aliasTargets : lg->GetMakefile()->GetAliasTargets()) { if (aliasTargets.second == itemName) { - nameWithAliases += "\\n(" + aliasTargets.first + ")"; + items.push_back(aliasTargets.first); } } } + std::sort(items.begin(), items.end()); + items.erase(std::unique(items.begin(), items.end()), items.end()); + + auto nameWithAliases = itemName; + for(auto const& item : items) { + nameWithAliases += "\\n(" + item + ")"; + } + return nameWithAliases; } diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h index 9766068..d1300ac 100644 --- a/Source/cmGraphVizWriter.h +++ b/Source/cmGraphVizWriter.h @@ -46,9 +46,6 @@ public: void Write(); private: - using FileStreamMap = - std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>; - struct Connection { Connection(cmLinkItem s, cmLinkItem d, std::string scope) @@ -76,8 +73,8 @@ private: void WriteNode(cmGeneratedFileStream& fs, cmLinkItem const& item); - void CreateTargetFile(FileStreamMap& fileStreamMap, cmLinkItem const& target, - std::string const& fileNameSuffix = ""); + std::unique_ptr<cmGeneratedFileStream> CreateTargetFile( + cmLinkItem const& target, std::string const& fileNameSuffix = ""); void WriteConnection(cmGeneratedFileStream& fs, cmLinkItem const& dependerTargetName, @@ -95,7 +92,7 @@ private: template <typename DirFunc> void WritePerTargetConnections(const ConnectionsMap& connections, - const FileStreamMap& streams); + const std::string& fileNameSuffix = ""); bool ItemExcluded(cmLinkItem const& item); bool ItemNameFilteredOut(std::string const& itemName); @@ -111,8 +108,6 @@ private: std::string FileName; cmGeneratedFileStream GlobalFileStream; - FileStreamMap PerTargetFileStreams; - FileStreamMap TargetDependersFileStreams; ConnectionsMap PerTargetConnections; ConnectionsMap TargetDependersConnections; diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 178af73..83609e2 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -680,7 +680,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, if (createInstallGeneratorsForTargetFileSets && !namelinkOnly) { cmProp files = target.GetProperty("PRIVATE_HEADER"); - if (files && !files->empty()) { + if (cmNonempty(files)) { std::vector<std::string> relFiles = cmExpandedList(*files); std::vector<std::string> absFiles; if (!helper.MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) { @@ -702,7 +702,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, } files = target.GetProperty("PUBLIC_HEADER"); - if (files && !files->empty()) { + if (cmNonempty(files)) { std::vector<std::string> relFiles = cmExpandedList(*files); std::vector<std::string> absFiles; if (!helper.MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) { @@ -724,7 +724,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, } files = target.GetProperty("RESOURCE"); - if (files && !files->empty()) { + if (cmNonempty(files)) { std::vector<std::string> relFiles = cmExpandedList(*files); std::vector<std::string> absFiles; if (!helper.MakeFilesFullPath("RESOURCE", relFiles, absFiles)) { @@ -1157,7 +1157,7 @@ bool HandleDirectoryMode(std::vector<std::string> const& args, } else if (doing == DoingRegex) { literal_args += " REGEX \""; // Match rules are case-insensitive on some platforms. -#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__) +#if defined(_WIN32) || defined(__APPLE__) std::string regex = cmSystemTools::LowerCase(args[i]); #else std::string regex = args[i]; diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx index 9f17f15..3a2e3be 100644 --- a/Source/cmJsonObjects.cxx +++ b/Source/cmJsonObjects.cxx @@ -51,11 +51,7 @@ std::vector<std::string> getConfigurations(const cmake* cm) return configurations; } - makefiles[0]->GetConfigurations(configurations); - if (configurations.empty()) { - configurations.emplace_back(); - } - return configurations; + return makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); } bool hasString(const Json::Value& v, const std::string& s) diff --git a/Source/cmLinkItemGraphVisitor.cxx b/Source/cmLinkItemGraphVisitor.cxx index acc23c8..dfdd3ff 100644 --- a/Source/cmLinkItemGraphVisitor.cxx +++ b/Source/cmLinkItemGraphVisitor.cxx @@ -24,15 +24,12 @@ void cmLinkItemGraphVisitor::VisitItem(cmLinkItem const& item) void cmLinkItemGraphVisitor::VisitLinks(cmLinkItem const& item, cmLinkItem const& rootItem) { - if (this->LinkVisited(item, rootItem)) { - return; - } - if (item.Target == nullptr) { return; } - for (auto const& config : item.Target->Makefile->GetGeneratorConfigs()) { + for (auto const& config : item.Target->Makefile->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig)) { this->VisitLinks(item, rootItem, config); } } diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx index c50a786..5739fec 100644 --- a/Source/cmLinkLineDeviceComputer.cxx +++ b/Source/cmLinkLineDeviceComputer.cxx @@ -191,21 +191,18 @@ bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg, target.GetLinkClosure(config); if (cm::contains(closure->Languages, "CUDA")) { - if (cmProp separableCompilation = - target.GetProperty("CUDA_SEPARABLE_COMPILATION")) { - if (cmIsOn(*separableCompilation)) { - bool doDeviceLinking = false; - switch (target.GetType()) { - case cmStateEnums::SHARED_LIBRARY: - case cmStateEnums::MODULE_LIBRARY: - case cmStateEnums::EXECUTABLE: - doDeviceLinking = true; - break; - default: - break; - } - return doDeviceLinking; + if (cmIsOn(target.GetProperty("CUDA_SEPARABLE_COMPILATION"))) { + bool doDeviceLinking = false; + switch (target.GetType()) { + case cmStateEnums::SHARED_LIBRARY: + case cmStateEnums::MODULE_LIBRARY: + case cmStateEnums::EXECUTABLE: + doDeviceLinking = true; + break; + default: + break; } + return doDeviceLinking; } cmComputeLinkInformation* pcli = target.GetLinkInformation(config); diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index 89902ff..0b4414d 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -175,6 +175,32 @@ public: std::ostream& operator<<(std::ostream& os, BT<std::string> const& s); +// Wrap type T as a value with potentially multiple backtraces. For purposes +// of ordering and equality comparison, only the original value is used. The +// backtrace is considered incidental. +template <typename T> +class BTs +{ +public: + BTs(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace()) + : Value(std::move(v)) + { + Backtraces.emplace_back(std::move(bt)); + } + T Value; + std::vector<cmListFileBacktrace> Backtraces; + friend bool operator==(BTs<T> const& l, BTs<T> const& r) + { + return l.Value == r.Value; + } + friend bool operator<(BTs<T> const& l, BTs<T> const& r) + { + return l.Value < r.Value; + } + friend bool operator==(BTs<T> const& l, T const& r) { return l.Value == r; } + friend bool operator==(T const& l, BTs<T> const& r) { return l == r.Value; } +}; + std::vector<BT<std::string>> ExpandListWithBacktrace( std::string const& list, cmListFileBacktrace const& bt = cmListFileBacktrace()); diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx index 278ec8b..44db842 100644 --- a/Source/cmLocalCommonGenerator.cxx +++ b/Source/cmLocalCommonGenerator.cxx @@ -17,10 +17,8 @@ cmLocalCommonGenerator::cmLocalCommonGenerator(cmGlobalGenerator* gg, : cmLocalGenerator(gg, mf) , WorkingDirectory(std::move(wd)) { - this->Makefile->GetConfigurations(this->ConfigNames); - if (this->ConfigNames.empty()) { - this->ConfigNames.emplace_back(); - } + this->ConfigNames = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); } cmLocalCommonGenerator::~cmLocalCommonGenerator() = default; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index c15ca7c..2380cce 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -39,6 +39,7 @@ #include "cmSourceFile.h" #include "cmSourceFileLocation.h" #include "cmSourceFileLocationKind.h" +#include "cmStandardLevelResolver.h" #include "cmState.h" #include "cmStateDirectory.h" #include "cmStateTypes.h" @@ -129,7 +130,7 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile) this->LinkerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT"); } - if (std::string const* appleArchSysroots = + if (cmProp appleArchSysroots = this->Makefile->GetDef("CMAKE_APPLE_ARCH_SYSROOTS")) { std::string const& appleArchs = this->Makefile->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES"); @@ -220,7 +221,7 @@ void cmLocalGenerator::ComputeObjectMaxPath() this->ObjectPathMax = 1000; #endif const char* plen = this->Makefile->GetDefinition("CMAKE_OBJECT_PATH_MAX"); - if (plen && *plen) { + if (cmNonempty(plen)) { unsigned int pmax; if (sscanf(plen, "%u", &pmax) == 1) { if (pmax >= 128) { @@ -283,7 +284,7 @@ void cmLocalGenerator::TraceDependencies() // Generate the rule files for each target. const auto& targets = this->GetGeneratorTargets(); for (const auto& target : targets) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!target->IsInBuildSystem()) { continue; } target->TraceDependencies(); @@ -297,9 +298,9 @@ void cmLocalGenerator::GenerateTestFiles() } // Compute the set of configurations. - std::vector<std::string> configurationTypes; - const std::string& config = - this->Makefile->GetConfigurations(configurationTypes, false); + std::vector<std::string> configurationTypes = + this->Makefile->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig); + std::string config = this->Makefile->GetDefaultConfiguration(); std::string file = cmStrCat(this->StateSnapshot.GetDirectory().GetCurrentBinary(), @@ -379,7 +380,7 @@ void cmLocalGenerator::GenerateTestFiles() void cmLocalGenerator::CreateEvaluationFileOutputs() { std::vector<std::string> const& configs = - this->Makefile->GetGeneratorConfigs(); + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); for (std::string const& c : configs) { this->CreateEvaluationFileOutputs(c); } @@ -433,7 +434,7 @@ void cmLocalGenerator::GenerateInstallRules() prefix_win32 = "C:"; } const char* project_name = this->Makefile->GetDefinition("PROJECT_NAME"); - if (project_name && project_name[0]) { + if (cmNonempty(project_name)) { prefix_win32 += "/Program Files/"; prefix_win32 += project_name; } else { @@ -462,9 +463,9 @@ void cmLocalGenerator::GenerateInstallRules() } // Compute the set of configurations. - std::vector<std::string> configurationTypes; - const std::string& config = - this->Makefile->GetConfigurations(configurationTypes, false); + std::vector<std::string> configurationTypes = + this->Makefile->GetGeneratorConfigs(cmMakefile::OnlyMultiConfig); + std::string config = this->Makefile->GetDefaultConfiguration(); // Choose a default install configuration. std::string default_config = config; @@ -753,16 +754,13 @@ cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget( void cmLocalGenerator::ComputeTargetManifest() { // Collect the set of configuration types. - std::vector<std::string> configNames; - this->Makefile->GetConfigurations(configNames); - if (configNames.empty()) { - configNames.emplace_back(); - } + std::vector<std::string> configNames = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); // Add our targets to the manifest for each configuration. const auto& targets = this->GetGeneratorTargets(); for (const auto& target : targets) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!target->IsInBuildSystem()) { continue; } for (std::string const& c : configNames) { @@ -774,11 +772,8 @@ void cmLocalGenerator::ComputeTargetManifest() bool cmLocalGenerator::ComputeTargetCompileFeatures() { // Collect the set of configuration types. - std::vector<std::string> configNames; - this->Makefile->GetConfigurations(configNames); - if (configNames.empty()) { - configNames.emplace_back(); - } + std::vector<std::string> configNames = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); using LanguagePair = std::pair<std::string, std::string>; std::vector<LanguagePair> pairedLanguages{ { "OBJC", "C" }, @@ -802,40 +797,9 @@ bool cmLocalGenerator::ComputeTargetCompileFeatures() // Now that C/C++ _STANDARD values have been computed // set the values to ObjC/ObjCXX _STANDARD variables - if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - auto copyStandardToObjLang = [&](LanguagePair const& lang) -> bool { - if (!target->GetProperty(cmStrCat(lang.first, "_STANDARD"))) { - cmProp standard = - target->GetProperty(cmStrCat(lang.second, "_STANDARD")); - if (!standard) { - standard = this->Makefile->GetDef( - cmStrCat("CMAKE_", lang.second, "_STANDARD_DEFAULT")); - } - target->Target->SetProperty(cmStrCat(lang.first, "_STANDARD"), - standard ? standard->c_str() : nullptr); - return true; - } - return false; - }; - auto copyPropertyToObjLang = [&](LanguagePair const& lang, - const char* property) { - if (!target->GetProperty(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) { - if (copyStandardToObjLang(lang)) { - copyPropertyToObjLang(lang, "_STANDARD_REQUIRED"); - copyPropertyToObjLang(lang, "_EXTENSIONS"); - } - } - if (cmProp standard = target->GetProperty("CUDA_STANDARD")) { - if (*standard == "98") { - target->Target->SetProperty("CUDA_STANDARD", "03"); - } + if (target->CanCompileSources()) { + for (std::string const& c : configNames) { + target->ComputeCompileFeatures(c, inferredEnabledLanguages); } } } @@ -929,7 +893,7 @@ std::string cmLocalGenerator::GetIncludeFlags( emitted.insert("/System/Library/Frameworks"); #endif for (std::string const& i : includes) { - if (fwSearchFlag && *fwSearchFlag && this->Makefile->IsOn("APPLE") && + if (cmNonempty(fwSearchFlag) && this->Makefile->IsOn("APPLE") && cmSystemTools::IsPathToFramework(i)) { std::string const frameworkDir = cmSystemTools::CollapseFullPath(cmStrCat(i, "/../")); @@ -1025,12 +989,13 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, this->AppendCompileOptions(flags, targetCompileOpts); } + cmStandardLevelResolver standardResolver(this->Makefile); for (auto const& it : target->GetMaxLanguageStandards()) { - cmProp standard = target->GetProperty(it.first + "_STANDARD"); + cmProp standard = target->GetLanguageStandard(it.first, config); if (!standard) { continue; } - if (this->Makefile->IsLaterStandard(it.first, *standard, it.second)) { + if (standardResolver.IsLaterStandard(it.first, *standard, it.second)) { std::ostringstream e; e << "The COMPILE_FEATURES property of target \"" << target->GetName() << "\" was evaluated when computing the link " @@ -1050,7 +1015,7 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, } std::string compReqFlag; - this->AddCompilerRequirementFlag(compReqFlag, target, lang); + this->AddCompilerRequirementFlag(compReqFlag, target, lang, config); if (!compReqFlag.empty()) { flags.emplace_back(std::move(compReqFlag)); } @@ -1308,7 +1273,7 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit( } } - // Emit remaining non implicit user direcories. + // Emit remaining non implicit user directories. for (BT<std::string> const& udr : userDirs) { if (notExcluded(udr.Value)) { emitBT(udr); @@ -1578,9 +1543,8 @@ void cmLocalGenerator::GetTargetFlags( frameworkPath, linkPath); } - if (cmIsOn(this->Makefile->GetDefinition("BUILD_SHARED_LIBS"))) { - std::string sFlagVar = std::string("CMAKE_SHARED_BUILD_") + - linkLanguage + std::string("_FLAGS"); + if (this->Makefile->IsOn("BUILD_SHARED_LIBS")) { + std::string sFlagVar = "CMAKE_SHARED_BUILD_" + linkLanguage + "_FLAGS"; exeFlags += this->Makefile->GetSafeDefinition(sFlagVar); exeFlags += " "; } @@ -1689,7 +1653,7 @@ static std::string GetFrameworkFlags(const std::string& lang, std::string fwSearchFlagVar = "CMAKE_" + lang + "_FRAMEWORK_SEARCH_FLAG"; const char* fwSearchFlag = mf->GetDefinition(fwSearchFlagVar); - if (!(fwSearchFlag && *fwSearchFlag)) { + if (!cmNonempty(fwSearchFlag)) { return std::string(); } @@ -1928,7 +1892,7 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, std::string sysrootFlagVar = std::string("CMAKE_") + lang + "_SYSROOT_FLAG"; const char* sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar); - if (sysrootFlag && *sysrootFlag) { + if (cmNonempty(sysrootFlag)) { if (!this->AppleArchSysroots.empty() && !this->AllAppleArchSysrootsAreTheSame(archs, sysroot)) { for (std::string const& arch : archs) { @@ -1957,8 +1921,7 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, std::string("CMAKE_") + lang + "_OSX_DEPLOYMENT_TARGET_FLAG"; const char* deploymentTargetFlag = this->Makefile->GetDefinition(deploymentTargetFlagVar); - if (deploymentTargetFlag && *deploymentTargetFlag && deploymentTarget && - *deploymentTarget) { + if (cmNonempty(deploymentTargetFlag) && cmNonempty(deploymentTarget)) { flags += " "; flags += deploymentTargetFlag; flags += deploymentTarget; @@ -1975,6 +1938,9 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags, this->AddConfigVariableFlags(flags, cmStrCat("CMAKE_", lang, "_FLAGS"), config); + std::string const& compiler = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_COMPILER_ID")); + if (lang == "Swift") { if (cmProp v = target->GetProperty("Swift_LANGUAGE_VERSION")) { if (cmSystemTools::VersionCompare( @@ -1988,9 +1954,6 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags, 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"); @@ -2002,12 +1965,29 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags, } } } - + // Add VFS Overlay for Clang compiliers + if (compiler == "Clang") { + if (const char* vfsOverlay = + this->Makefile->GetDefinition("CMAKE_CLANG_VFS_OVERLAY")) { + std::string const& compilerSimulateId = + this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_SIMULATE_ID")); + if (compilerSimulateId == "MSVC") { + this->AppendCompileOptions( + flags, + std::vector<std::string>{ "-Xclang", "-ivfsoverlay", "-Xclang", + vfsOverlay }); + } else { + this->AppendCompileOptions( + flags, std::vector<std::string>{ "-ivfsoverlay", vfsOverlay }); + } + } + } // Add MSVC runtime library flags. This is activated by the presence // of a default selection whether or not it is overridden by a property. cmProp msvcRuntimeLibraryDefault = this->Makefile->GetDef("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT"); - if (msvcRuntimeLibraryDefault && !msvcRuntimeLibraryDefault->empty()) { + if (cmNonempty(msvcRuntimeLibraryDefault)) { cmProp msvcRuntimeLibraryValue = target->GetProperty("MSVC_RUNTIME_LIBRARY"); if (!msvcRuntimeLibraryValue) { @@ -2046,7 +2026,7 @@ void cmLocalGenerator::AddLanguageFlagsForLinking( // when linking in order to use the matching standard library. // FIXME: If CMake gains an abstraction for standard library // selection, this will have to be reconciled with it. - this->AddCompilerRequirementFlag(flags, target, lang); + this->AddCompilerRequirementFlag(flags, target, lang, config); } this->AddLanguageFlags(flags, target, lang, config); @@ -2189,156 +2169,20 @@ void cmLocalGenerator::AddSharedFlags(std::string& flags, } void cmLocalGenerator::AddCompilerRequirementFlag( - std::string& flags, cmGeneratorTarget const* target, const std::string& lang) + std::string& flags, cmGeneratorTarget const* target, const std::string& lang, + const std::string& config) { - if (lang.empty()) { - return; - } - const char* defaultStd = - this->Makefile->GetDefinition("CMAKE_" + lang + "_STANDARD_DEFAULT"); - if (!defaultStd || !*defaultStd) { - // This compiler has no notion of language standard levels. - return; - } - std::string extProp = lang + "_EXTENSIONS"; - bool ext = true; - if (cmProp extPropValue = target->GetProperty(extProp)) { - if (cmIsOff(*extPropValue)) { - ext = false; - } - } - std::string stdProp = lang + "_STANDARD"; - cmProp standardProp = target->GetProperty(stdProp); - if (!standardProp) { - if (ext) { - // No language standard is specified and extensions are not disabled. - // Check if this compiler needs a flag to enable extensions. - std::string const option_flag = - "CMAKE_" + lang + "_EXTENSION_COMPILE_OPTION"; - if (const char* opt = - target->Target->GetMakefile()->GetDefinition(option_flag)) { - std::vector<std::string> optVec = cmExpandedList(opt); - for (std::string const& i : optVec) { - this->AppendFlagEscape(flags, i); - } - } - } - return; - } - - std::string const type = ext ? "EXTENSION" : "STANDARD"; + cmStandardLevelResolver standardResolver(this->Makefile); - if (target->GetPropertyAsBool(lang + "_STANDARD_REQUIRED")) { - std::string option_flag = - "CMAKE_" + lang + *standardProp + "_" + type + "_COMPILE_OPTION"; - - const char* opt = - target->Target->GetMakefile()->GetDefinition(option_flag); - if (!opt) { - std::ostringstream e; - e << "Target \"" << target->GetName() - << "\" requires the language " - "dialect \"" - << lang << *standardProp << "\" " - << (ext ? "(with compiler extensions)" : "") - << ", but CMake " - "does not know the compile flags to use to enable it."; - this->IssueMessage(MessageType::FATAL_ERROR, e.str()); - } else { - std::vector<std::string> optVec = cmExpandedList(opt); - for (std::string const& i : optVec) { - this->AppendFlagEscape(flags, i); - } - } - return; - } - - static std::map<std::string, std::vector<std::string>> langStdMap; - if (langStdMap.empty()) { - // Maintain sorted order, most recent first. - langStdMap["CXX"].emplace_back("20"); - langStdMap["CXX"].emplace_back("17"); - langStdMap["CXX"].emplace_back("14"); - langStdMap["CXX"].emplace_back("11"); - langStdMap["CXX"].emplace_back("98"); - - langStdMap["OBJCXX"].emplace_back("20"); - langStdMap["OBJCXX"].emplace_back("17"); - langStdMap["OBJCXX"].emplace_back("14"); - langStdMap["OBJCXX"].emplace_back("11"); - langStdMap["OBJCXX"].emplace_back("98"); - - langStdMap["C"].emplace_back("11"); - langStdMap["C"].emplace_back("99"); - langStdMap["C"].emplace_back("90"); - - langStdMap["OBJC"].emplace_back("11"); - langStdMap["OBJC"].emplace_back("99"); - langStdMap["OBJC"].emplace_back("90"); - - langStdMap["CUDA"].emplace_back("20"); - langStdMap["CUDA"].emplace_back("17"); - langStdMap["CUDA"].emplace_back("14"); - langStdMap["CUDA"].emplace_back("11"); - langStdMap["CUDA"].emplace_back("03"); - } - - std::string standard(*standardProp); - if (lang == "CUDA" && standard == "98") { - standard = "03"; - } - std::vector<std::string>& stds = langStdMap[lang]; - - auto stdIt = std::find(stds.begin(), stds.end(), standard); - if (stdIt == stds.end()) { - - std::string e = - lang + "_STANDARD is set to invalid value '" + standard + "'"; - this->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, e, target->GetBacktrace()); - return; - } - - auto defaultStdIt = std::find(stds.begin(), stds.end(), defaultStd); - if (defaultStdIt == stds.end()) { - std::string e = "CMAKE_" + lang + - "_STANDARD_DEFAULT is set to invalid value '" + std::string(defaultStd) + - "'"; - this->IssueMessage(MessageType::INTERNAL_ERROR, e); - return; - } - - // If the standard requested is older than the compiler's default - // then we need to use a flag to change it. The comparison is - // greater-or-equal because the standards are stored in backward - // chronological order. - if (stdIt >= defaultStdIt) { - std::string option_flag = - "CMAKE_" + lang + *stdIt + "_" + type + "_COMPILE_OPTION"; - - std::string const& opt = - target->Target->GetMakefile()->GetRequiredDefinition(option_flag); - std::vector<std::string> optVec = cmExpandedList(opt); - for (std::string const& i : optVec) { - this->AppendFlagEscape(flags, i); - } - return; - } - - // The standard requested is at least as new as the compiler's default, - // and the standard request is not required. Decay to the newest standard - // for which a flag is defined. - for (; stdIt < defaultStdIt; ++stdIt) { - std::string option_flag = - cmStrCat("CMAKE_", lang, *stdIt, "_", type, "_COMPILE_OPTION"); - - if (const char* opt = - target->Target->GetMakefile()->GetDefinition(option_flag)) { + std::string const& optionFlagDef = + standardResolver.GetCompileOptionDef(target, lang, config); + if (!optionFlagDef.empty()) { + auto opt = target->Target->GetMakefile()->GetDefinition(optionFlagDef); + if (opt) { std::vector<std::string> optVec = cmExpandedList(opt); for (std::string const& i : optVec) { this->AppendFlagEscape(flags, i); } - return; } } } @@ -2583,11 +2427,8 @@ void cmLocalGenerator::AppendFlagEscape(std::string& flags, void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) { - std::vector<std::string> configsList; - std::string configDefault = this->Makefile->GetConfigurations(configsList); - if (configsList.empty()) { - configsList.push_back(configDefault); - } + std::vector<std::string> configsList = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); for (std::string const& config : configsList) { // FIXME: Refactor collection of sources to not evaluate object @@ -3236,7 +3077,7 @@ void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines, if (!lang.empty()) { const char* df = this->Makefile->GetDefinition(cmStrCat("CMAKE_", lang, "_DEFINE_FLAG")); - if (df && *df) { + if (cmNonempty(df)) { dflag = df; } } @@ -3291,8 +3132,8 @@ void cmLocalGenerator::AppendFeatureOptions(std::string& flags, } } -const char* cmLocalGenerator::GetFeature(const std::string& feature, - const std::string& config) +cmProp cmLocalGenerator::GetFeature(const std::string& feature, + const std::string& config) { std::string featureName = feature; // TODO: Define accumulation policy for features (prepend, append, @@ -3304,7 +3145,7 @@ const char* cmLocalGenerator::GetFeature(const std::string& feature, cmStateSnapshot snp = this->StateSnapshot; while (snp.IsValid()) { if (cmProp value = snp.GetDirectory().GetProperty(featureName)) { - return value->c_str(); + return value; } snp = snp.GetBuildsystemDirectoryParent(); } @@ -3845,8 +3686,7 @@ void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target, { // Find the Info.plist template. cmProp in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST"); - std::string inFile = - (in && !in->empty()) ? *in : "MacOSXBundleInfo.plist.in"; + std::string inFile = cmNonempty(in) ? *in : "MacOSXBundleInfo.plist.in"; if (!cmSystemTools::FileIsFullPath(inFile)) { std::string inMod = this->Makefile->GetModulesFile(inFile); if (!inMod.empty()) { @@ -3876,7 +3716,7 @@ void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target, cmLGInfoProp(mf, target, "MACOSX_BUNDLE_SHORT_VERSION_STRING"); cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_VERSION"); cmLGInfoProp(mf, target, "MACOSX_BUNDLE_COPYRIGHT"); - mf->ConfigureFile(inFile, fname, false, false, false); + mf->ConfigureFile(inFile, fname, false, false, false, true); } void cmLocalGenerator::GenerateFrameworkInfoPList( @@ -3885,8 +3725,7 @@ void cmLocalGenerator::GenerateFrameworkInfoPList( { // Find the Info.plist template. cmProp in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST"); - std::string inFile = - (in && !in->empty()) ? *in : "MacOSXFrameworkInfo.plist.in"; + std::string inFile = cmNonempty(in) ? *in : "MacOSXFrameworkInfo.plist.in"; if (!cmSystemTools::FileIsFullPath(inFile)) { std::string inMod = this->Makefile->GetModulesFile(inFile); if (!inMod.empty()) { @@ -3912,7 +3751,7 @@ void cmLocalGenerator::GenerateFrameworkInfoPList( cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_IDENTIFIER"); cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_SHORT_VERSION_STRING"); cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION"); - mf->ConfigureFile(inFile, fname, false, false, false); + mf->ConfigureFile(inFile, fname, false, false, false, true); } namespace { diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index f2d9145..0c51a65 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -20,6 +20,7 @@ #include "cmMessageType.h" #include "cmOutputConverter.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmStateSnapshot.h" class cmComputeLinkInformation; @@ -123,7 +124,8 @@ public: const std::string& config); void AddCompilerRequirementFlag(std::string& flags, cmGeneratorTarget const* target, - const std::string& lang); + const std::string& lang, + const std::string& config); //! Append flags to a string. virtual void AppendFlags(std::string& flags, const std::string& newFlags) const; @@ -208,8 +210,7 @@ public: void AppendFeatureOptions(std::string& flags, const std::string& lang, const char* feature); - const char* GetFeature(const std::string& feature, - const std::string& config); + cmProp GetFeature(const std::string& feature, const std::string& config); /** \brief Get absolute path to dependency \a name * diff --git a/Source/cmLocalGhsMultiGenerator.cxx b/Source/cmLocalGhsMultiGenerator.cxx index 098fa5a..a23ad57 100644 --- a/Source/cmLocalGhsMultiGenerator.cxx +++ b/Source/cmLocalGhsMultiGenerator.cxx @@ -11,7 +11,6 @@ #include "cmGhsMultiTargetGenerator.h" #include "cmGlobalGenerator.h" #include "cmSourceFile.h" -#include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -33,7 +32,7 @@ std::string cmLocalGhsMultiGenerator::GetTargetDirectory( void cmLocalGhsMultiGenerator::GenerateTargetsDepthFirst( cmGeneratorTarget* target, std::vector<cmGeneratorTarget*>& remaining) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!target->IsInBuildSystem()) { return; } // Find this target in the list of remaining targets. diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 87e8aa4..eb841d9 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -84,13 +84,31 @@ void cmLocalNinjaGenerator::Generate() if (!showIncludesPrefix.empty()) { cmGlobalNinjaGenerator::WriteComment(this->GetRulesFileStream(), "localized /showIncludes string"); - this->GetRulesFileStream() - << "msvc_deps_prefix = " << showIncludesPrefix << "\n\n"; + this->GetRulesFileStream() << "msvc_deps_prefix = "; +#ifdef WIN32 + // Ninja uses the ANSI Windows APIs, so strings in the rules file + // typically need to be ANSI encoded. However, in this case the compiler + // is being invoked using the UTF-8 codepage so the /showIncludes prefix + // will be UTF-8 encoded on stdout. Ninja can't successfully compare this + // UTF-8 encoded prefix to the ANSI encoded msvc_deps_prefix if it + // contains any non-ASCII characters and dependency checking will fail. + // As a workaround, leave the msvc_deps_prefix UTF-8 encoded even though + // the rest of the file is ANSI encoded. + if (GetConsoleOutputCP() == CP_UTF8 && GetACP() != CP_UTF8) { + this->GetRulesFileStream().WriteRaw(showIncludesPrefix); + } else { + this->GetRulesFileStream() << showIncludesPrefix; + } +#else + // It's safe to use the standard encoding on other platforms. + this->GetRulesFileStream() << showIncludesPrefix; +#endif + this->GetRulesFileStream() << "\n\n"; } } for (const auto& target : this->GetGeneratorTargets()) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!target->IsInBuildSystem()) { continue; } auto tg = cmNinjaTargetGenerator::New(target.get()); @@ -102,9 +120,10 @@ void cmLocalNinjaGenerator::Generate() this->GetGlobalGenerator()->IsMultiConfig()) { cmNinjaBuild phonyAlias("phony"); this->GetGlobalNinjaGenerator()->AppendTargetOutputs( - target.get(), phonyAlias.Outputs, ""); + target.get(), phonyAlias.Outputs, "", DependOnTargetArtifact); this->GetGlobalNinjaGenerator()->AppendTargetOutputs( - target.get(), phonyAlias.ExplicitDeps, config); + target.get(), phonyAlias.ExplicitDeps, config, + DependOnTargetArtifact); this->GetGlobalNinjaGenerator()->WriteBuild( *this->GetGlobalNinjaGenerator()->GetConfigFileStream(config), phonyAlias); @@ -115,11 +134,12 @@ void cmLocalNinjaGenerator::Generate() if (!this->GetGlobalNinjaGenerator()->GetDefaultConfigs().empty()) { cmNinjaBuild phonyAlias("phony"); this->GetGlobalNinjaGenerator()->AppendTargetOutputs( - target.get(), phonyAlias.Outputs, ""); + target.get(), phonyAlias.Outputs, "", DependOnTargetArtifact); for (auto const& config : this->GetGlobalNinjaGenerator()->GetDefaultConfigs()) { this->GetGlobalNinjaGenerator()->AppendTargetOutputs( - target.get(), phonyAlias.ExplicitDeps, config); + target.get(), phonyAlias.ExplicitDeps, config, + DependOnTargetArtifact); } this->GetGlobalNinjaGenerator()->WriteBuild( *this->GetGlobalNinjaGenerator()->GetDefaultFileStream(), @@ -127,10 +147,11 @@ void cmLocalNinjaGenerator::Generate() } cmNinjaBuild phonyAlias("phony"); this->GetGlobalNinjaGenerator()->AppendTargetOutputs( - target.get(), phonyAlias.Outputs, "all"); + target.get(), phonyAlias.Outputs, "all", DependOnTargetArtifact); for (auto const& config : this->GetConfigNames()) { this->GetGlobalNinjaGenerator()->AppendTargetOutputs( - target.get(), phonyAlias.ExplicitDeps, config); + target.get(), phonyAlias.ExplicitDeps, config, + DependOnTargetArtifact); } this->GetGlobalNinjaGenerator()->WriteBuild( *this->GetGlobalNinjaGenerator()->GetDefaultFileStream(), @@ -355,8 +376,8 @@ void cmLocalNinjaGenerator::AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs, const std::string& config) { - this->GetGlobalNinjaGenerator()->AppendTargetOutputs(target, outputs, - config); + this->GetGlobalNinjaGenerator()->AppendTargetOutputs(target, outputs, config, + DependOnTargetArtifact); } void cmLocalNinjaGenerator::AppendTargetDepends(cmGeneratorTarget* target, @@ -668,7 +689,7 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( { cmProp property_value = this->Makefile->GetProperty("RULE_LAUNCH_CUSTOM"); - if (!property_value || property_value->empty()) { + if (!cmNonempty(property_value)) { return std::string(); } diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h index ef160e7..73c0cde 100644 --- a/Source/cmLocalNinjaGenerator.h +++ b/Source/cmLocalNinjaGenerator.h @@ -66,10 +66,10 @@ public: void AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs, const std::string& config); - void AppendTargetDepends( - cmGeneratorTarget* target, cmNinjaDeps& outputs, const std::string& config, - const std::string& fileConfig, - cmNinjaTargetDepends depends = DependOnTargetArtifact); + void AppendTargetDepends(cmGeneratorTarget* target, cmNinjaDeps& outputs, + const std::string& config, + const std::string& fileConfig, + cmNinjaTargetDepends depends); void AddCustomCommandTarget(cmCustomCommand const* cc, cmGeneratorTarget* target); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index de1461a..8acd1e3 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -101,7 +101,7 @@ void cmLocalUnixMakefileGenerator3::Generate() cmGlobalUnixMakefileGenerator3* gg = static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator); for (const auto& target : this->GetGeneratorTargets()) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!target->IsInBuildSystem()) { continue; } std::unique_ptr<cmMakefileTargetGenerator> tg( @@ -137,7 +137,7 @@ void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles( std::map<std::string, LocalObjectInfo>& localObjectFiles) { for (const auto& gt : this->GetGeneratorTargets()) { - if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!gt->CanCompileSources()) { continue; } std::vector<cmSourceFile const*> objectSources; @@ -950,7 +950,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::string launcher; // Short-circuit if there is no launcher. const char* val = this->GetRuleLauncher(target, "RULE_LAUNCH_CUSTOM"); - if (val && *val) { + if (cmNonempty(val)) { // Expand rule variables referenced in the given launcher command. cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = target->GetName().c_str(); @@ -1744,7 +1744,7 @@ public: return false; } // If it's an absolute path, check if it starts with the source - // direcotory: + // directory: return ( !(IsInDirectory(SourceDir, path) || IsInDirectory(BinaryDir, path))); } @@ -1807,7 +1807,7 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( std::string cidVar = cmStrCat("CMAKE_", implicitLang.first, "_COMPILER_ID"); const char* cid = this->Makefile->GetDefinition(cidVar); - if (cid && *cid) { + if (cmNonempty(cid)) { cmakefileStream << "set(CMAKE_" << implicitLang.first << "_COMPILER_ID \"" << cid << "\")\n"; } diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx index 9076e26..6c7d6c6 100644 --- a/Source/cmLocalVisualStudio10Generator.cxx +++ b/Source/cmLocalVisualStudio10Generator.cxx @@ -69,7 +69,7 @@ cmLocalVisualStudio10Generator::~cmLocalVisualStudio10Generator() void cmLocalVisualStudio10Generator::GenerateTargetsDepthFirst( cmGeneratorTarget* target, std::vector<cmGeneratorTarget*>& remaining) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!target->IsInBuildSystem()) { return; } // Find this target in the list of remaining targets. diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 5d50e2d..50ffe8d 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -66,7 +66,7 @@ void cmLocalVisualStudio7Generator::AddHelperCommands() // Now create GUIDs for targets const auto& tgts = this->GetGeneratorTargets(); for (const auto& l : tgts) { - if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!l->IsInBuildSystem()) { continue; } cmProp path = l->GetProperty("EXTERNAL_MSPROJECT"); @@ -129,7 +129,7 @@ void cmLocalVisualStudio7Generator::WriteProjectFiles() // Create the project file for each target. for (const auto& l : tgts) { - if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!l->IsInBuildSystem()) { continue; } // INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace @@ -629,9 +629,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( break; case cmStateEnums::UTILITY: case cmStateEnums::GLOBAL_TARGET: + case cmStateEnums::INTERFACE_LIBRARY: configType = "10"; CM_FALLTHROUGH; - default: + case cmStateEnums::UNKNOWN_LIBRARY: targetBuilds = false; break; } @@ -1331,8 +1332,8 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, const std::string& libName, cmGeneratorTarget* target) { - std::vector<std::string> configs; - this->Makefile->GetConfigurations(configs); + std::vector<std::string> configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig); // We may be modifying the source groups temporarily, so make a copy. std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups(); @@ -1580,8 +1581,9 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( std::string cmLocalVisualStudio7Generator::ComputeLongestObjectDirectory( cmGeneratorTarget const* target) const { - std::vector<std::string> configs; - target->Target->GetMakefile()->GetConfigurations(configs); + std::vector<std::string> configs = + target->Target->GetMakefile()->GetGeneratorConfigs( + cmMakefile::ExcludeEmptyConfig); // Compute the maximum length configuration name. std::string config_max; @@ -1637,7 +1639,8 @@ bool cmLocalVisualStudio7Generator::WriteGroup( std::string source = sf->GetFullPath(); if (source != libName || target->GetType() == cmStateEnums::UTILITY || - target->GetType() == cmStateEnums::GLOBAL_TARGET) { + target->GetType() == cmStateEnums::GLOBAL_TARGET || + target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { // Look up the source kind and configs. std::map<cmSourceFile const*, size_t>::const_iterator map_it = sources.Index.find(sf); @@ -1936,6 +1939,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStartFortran( const char* keyword = p ? p->c_str() : "Console Application"; const char* projectType = 0; switch (target->GetType()) { + case cmStateEnums::OBJECT_LIBRARY: case cmStateEnums::STATIC_LIBRARY: projectType = "typeStaticLibrary"; if (keyword) { @@ -1957,7 +1961,8 @@ void cmLocalVisualStudio7Generator::WriteProjectStartFortran( break; case cmStateEnums::UTILITY: case cmStateEnums::GLOBAL_TARGET: - default: + case cmStateEnums::INTERFACE_LIBRARY: + case cmStateEnums::UNKNOWN_LIBRARY: break; } if (projectType) { diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index db5cee9..5cfe5f1 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -20,8 +20,10 @@ #include <cmext/algorithm> #include <cmext/string_view> -#include <cm3p/json/value.h> -#include <cm3p/json/writer.h> +#ifndef CMAKE_BOOTSTRAP +# include <cm3p/json/value.h> +# include <cm3p/json/writer.h> +#endif #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" @@ -34,6 +36,7 @@ #include "cmExecutionStatus.h" #include "cmExpandedCommandArgument.h" // IWYU pragma: keep #include "cmExportBuildFileGenerator.h" +#include "cmFSPermissions.h" #include "cmFileLockPool.h" #include "cmFunctionBlocker.h" #include "cmGeneratedFileStream.h" @@ -68,6 +71,8 @@ class cmMessenger; +using namespace cmFSPermissions; + cmDirectoryId::cmDirectoryId(std::string s) : String(std::move(s)) { @@ -82,7 +87,6 @@ cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator, { this->IsSourceFileTryCompile = false; - this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused(); this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars(); this->SuppressSideEffects = false; @@ -194,7 +198,7 @@ void cmMakefile::MaybeWarnCMP0074(std::string const& pkg) std::string env; cmSystemTools::GetEnv(varName, env); - bool const haveVar = var && *var; + bool const haveVar = cmNonempty(var); bool const haveEnv = !env.empty(); if ((haveVar || haveEnv) && this->WarnedCMP0074.insert(varName).second) { std::ostringstream w; @@ -750,7 +754,6 @@ void cmMakefile::ReadListFile(cmListFile const& listFile, break; } } - this->CheckForUnusedVariables(); this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile); this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile); @@ -1434,8 +1437,8 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent) if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) { cmProp p = parent->GetProperty("COMPILE_DEFINITIONS"); this->SetProperty("COMPILE_DEFINITIONS", p ? p->c_str() : nullptr); - std::vector<std::string> configs; - this->GetConfigurations(configs); + std::vector<std::string> configs = + this->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig); for (std::string const& config : configs) { std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config)); @@ -1513,8 +1516,6 @@ void cmMakefile::PopFunctionScope(bool reportError) #endif this->PopLoopBlockBarrier(); - - this->CheckForUnusedVariables(); } void cmMakefile::PushMacroScope(std::string const& fileName, @@ -1661,7 +1662,8 @@ void cmMakefile::Configure() this->SetCheckCMP0000(true); // Implicitly set the version for the user. - this->SetPolicyVersion("2.4", std::string()); + cmPolicies::ApplyPolicyVersion(this, 2, 4, 0, + cmPolicies::WarnCompat::Off); } } bool hasProject = false; @@ -1860,9 +1862,6 @@ void cmMakefile::AddSystemIncludeDirectories(const std::set<std::string>& incs) void cmMakefile::AddDefinition(const std::string& name, cm::string_view value) { - if (this->VariableInitialized(name)) { - this->LogUnused("changing definition", name); - } this->StateSnapshot.SetDefinition(name, value); #ifndef CMAKE_BOOTSTRAP @@ -1923,16 +1922,6 @@ void cmMakefile::AddCacheDefinition(const std::string& name, const char* value, this->StateSnapshot.RemoveDefinition(name); } -void cmMakefile::CheckForUnusedVariables() const -{ - if (!this->WarnUnused) { - return; - } - for (const std::string& key : this->StateSnapshot.UnusedKeys()) { - this->LogUnused("out of scope", key); - } -} - void cmMakefile::MarkVariableAsUsed(const std::string& var) { this->StateSnapshot.GetDefinition(var); @@ -1960,29 +1949,8 @@ void cmMakefile::MaybeWarnUninitialized(std::string const& variable, } } -void cmMakefile::LogUnused(const char* reason, const std::string& name) const -{ - if (this->WarnUnused) { - std::string path; - if (!this->ExecutionStatusStack.empty()) { - path = this->GetExecutionContext().FilePath; - } else { - path = cmStrCat(this->GetCurrentSourceDirectory(), "/CMakeLists.txt"); - } - - if (this->CheckSystemVars || this->IsProjectFile(path.c_str())) { - std::ostringstream msg; - msg << "unused variable (" << reason << ") \'" << name << "\'"; - this->IssueMessage(MessageType::AUTHOR_WARNING, msg.str()); - } - } -} - void cmMakefile::RemoveDefinition(const std::string& name) { - if (this->VariableInitialized(name)) { - this->LogUnused("unsetting", name); - } this->StateSnapshot.RemoveDefinition(name); #ifndef CMAKE_BOOTSTRAP cmVariableWatch* vv = this->GetVariableWatch(); @@ -2555,8 +2523,7 @@ void cmMakefile::ExpandVariablesCMP0019() bool cmMakefile::IsOn(const std::string& name) const { - const char* value = this->GetDefinition(name); - return cmIsOn(value); + return cmIsOn(this->GetDef(name)); } bool cmMakefile::IsSet(const std::string& name) const @@ -3287,25 +3254,28 @@ void cmMakefile::RemoveVariablesInString(std::string& source, } } -std::string cmMakefile::GetConfigurations(std::vector<std::string>& configs, - bool singleConfig) const +std::string cmMakefile::GetDefaultConfiguration() const { if (this->GetGlobalGenerator()->IsMultiConfig()) { - this->GetDefExpandList("CMAKE_CONFIGURATION_TYPES", configs); - return ""; - } - const std::string& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); - if (singleConfig && !buildType.empty()) { - configs.push_back(buildType); + return std::string{}; } - return buildType; + return this->GetSafeDefinition("CMAKE_BUILD_TYPE"); } -std::vector<std::string> cmMakefile::GetGeneratorConfigs() const +std::vector<std::string> cmMakefile::GetGeneratorConfigs( + GeneratorConfigQuery mode) const { std::vector<std::string> configs; - GetConfigurations(configs); - if (configs.empty()) { + if (this->GetGlobalGenerator()->IsMultiConfig() || + mode == cmMakefile::OnlyMultiConfig) { + this->GetDefExpandList("CMAKE_CONFIGURATION_TYPES", configs); + } else { + const std::string& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); + if (!buildType.empty()) { + configs.emplace_back(buildType); + } + } + if (mode == cmMakefile::IncludeEmptyConfig && configs.empty()) { configs.emplace_back(); } return configs; @@ -3725,7 +3695,7 @@ int cmMakefile::TryCompile(const std::string& srcdir, if (cmakeArgs) { // FIXME: Workaround to ignore unused CLI variables in try-compile. // - // Ideally we should use SetArgs to honor options like --warn-unused-vars. + // Ideally we should use SetArgs for options like --no-warn-unused-cli. // However, there is a subtle problem when certain arguments are passed to // a macro wrapping around try_compile or try_run that does not escape // semicolons in its parameters but just passes ${ARGV} or ${ARGN}. In @@ -3744,7 +3714,7 @@ int cmMakefile::TryCompile(const std::string& srcdir, // the value VAR=a is sufficient for the try_compile or try_run to get the // correct result. Calling SetArgs here would break such projects that // previously built. Instead we work around the issue by never reporting - // unused arguments and ignoring options such as --warn-unused-vars. + // unused arguments and ignoring options such as --no-warn-unused-cli. cm.SetWarnUnusedCli(false); // cm.SetArgs(*cmakeArgs, true); @@ -3998,6 +3968,7 @@ void cmMakefile::ConfigureString(const std::string& input, std::string& output, int cmMakefile::ConfigureFile(const std::string& infile, const std::string& outfile, bool copyonly, bool atOnly, bool escapeQuotes, + bool use_source_permissions, cmNewLineStyle newLine) { int res = 1; @@ -4021,7 +3992,13 @@ int cmMakefile::ConfigureFile(const std::string& infile, this->AddCMakeOutputFile(soutfile); mode_t perm = 0; - cmSystemTools::GetPermissions(sinfile, perm); + if (!use_source_permissions) { + perm = perm | mode_owner_read | mode_owner_write | mode_group_read | + mode_world_read; + } else { + cmSystemTools::GetPermissions(sinfile, perm); + } + std::string::size_type pos = soutfile.rfind('/'); if (pos != std::string::npos) { std::string path = soutfile.substr(0, pos); @@ -4030,6 +4007,13 @@ int cmMakefile::ConfigureFile(const std::string& infile, if (copyonly) { if (!cmSystemTools::CopyFileIfDifferent(sinfile, soutfile)) { + this->IssueMessage(MessageType::FATAL_ERROR, + cmSystemTools::GetLastSystemError()); + return 0; + } + if (!cmSystemTools::SetPermissions(soutfile, perm)) { + this->IssueMessage(MessageType::FATAL_ERROR, + cmSystemTools::GetLastSystemError()); return 0; } } else { @@ -4080,9 +4064,15 @@ int cmMakefile::ConfigureFile(const std::string& infile, fin.close(); fout.close(); if (!cmSystemTools::CopyFileIfDifferent(tempOutputFile, soutfile)) { + this->IssueMessage(MessageType::FATAL_ERROR, + cmSystemTools::GetLastSystemError()); res = 0; } else { - cmSystemTools::SetPermissions(soutfile, perm); + if (!cmSystemTools::SetPermissions(soutfile, perm)) { + this->IssueMessage(MessageType::FATAL_ERROR, + cmSystemTools::GetLastSystemError()); + res = 0; + } } cmSystemTools::RemoveFile(tempOutputFile); } @@ -4127,8 +4117,7 @@ cmProp cmMakefile::GetProperty(const std::string& prop, bool chain) const bool cmMakefile::GetPropertyAsBool(const std::string& prop) const { - cmProp p = this->GetProperty(prop); - return p && cmIsOn(*p); + return cmIsOn(this->GetProperty(prop)); } std::vector<std::string> cmMakefile::GetPropertyKeys() const @@ -4240,8 +4229,6 @@ void cmMakefile::PopScope() this->PopLoopBlockBarrier(); - this->CheckForUnusedVariables(); - this->PopSnapshot(); } @@ -4557,7 +4544,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::CMP0071 && + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0072 && !(this->GetCMakeInstance()->GetIsInTryCompile() && ( // Policies set by cmCoreTryCompile::TryCompileCode. @@ -4599,7 +4586,7 @@ void cmMakefile::PopSnapshot(bool reportError) // cmStateSnapshot manages nested policy scopes within it. // Since the scope corresponding to the snapshot is closing, // reject any still-open nested policy scopes with an error. - while (!this->StateSnapshot.CanPopPolicyScope()) { + while (this->StateSnapshot.CanPopPolicyScope()) { if (reportError) { this->IssueMessage(MessageType::FATAL_ERROR, "cmake_policy PUSH without matching POP"); @@ -4615,7 +4602,8 @@ void cmMakefile::PopSnapshot(bool reportError) bool cmMakefile::SetPolicyVersion(std::string const& version_min, std::string const& version_max) { - return cmPolicies::ApplyPolicyVersion(this, version_min, version_max); + return cmPolicies::ApplyPolicyVersion(this, version_min, version_max, + cmPolicies::WarnCompat::On); } bool cmMakefile::HasCMP0054AlreadyBeenReported( @@ -4651,674 +4639,6 @@ bool cmMakefile::IgnoreErrorsCMP0061() const return ignoreErrors; } -#define FEATURE_STRING(F) , #F -static const char* const C_FEATURES[] = { nullptr FOR_EACH_C_FEATURE( - FEATURE_STRING) }; - -static const char* const CXX_FEATURES[] = { nullptr FOR_EACH_CXX_FEATURE( - FEATURE_STRING) }; - -static const char* const CUDA_FEATURES[] = { nullptr FOR_EACH_CUDA_FEATURE( - FEATURE_STRING) }; -#undef FEATURE_STRING - -static const char* const C_STANDARDS[] = { "90", "99", "11" }; -static const char* const CXX_STANDARDS[] = { "98", "11", "14", "17", "20" }; -static const char* const CUDA_STANDARDS[] = { "03", "11", "14", "17", "20" }; - -bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, - const std::string& feature, - std::string* error) const -{ - if (cmGeneratorExpression::Find(feature) != std::string::npos) { - target->AppendProperty("COMPILE_FEATURES", feature); - return true; - } - - std::string lang; - if (!this->CompileFeatureKnown(target, feature, lang, error)) { - return false; - } - - const char* features = this->CompileFeaturesAvailable(lang, error); - if (!features) { - return false; - } - - std::vector<std::string> availableFeatures = cmExpandedList(features); - if (!cm::contains(availableFeatures, feature)) { - std::ostringstream e; - e << "The compiler feature \"" << feature << "\" is not known to " << lang - << " compiler\n\"" - << this->GetDefinition("CMAKE_" + lang + "_COMPILER_ID") - << "\"\nversion " - << this->GetDefinition("CMAKE_" + lang + "_COMPILER_VERSION") << "."; - if (error) { - *error = e.str(); - } else { - this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(), - this->Backtrace); - } - return false; - } - - target->AppendProperty("COMPILE_FEATURES", feature); - - if (lang == "C" || lang == "OBJC") { - return this->AddRequiredTargetCFeature(target, feature, lang, error); - } - if (lang == "CUDA") { - return this->AddRequiredTargetCudaFeature(target, feature, lang, error); - } - return this->AddRequiredTargetCxxFeature(target, feature, lang, error); -} - -bool cmMakefile::CompileFeatureKnown(cmTarget const* target, - const std::string& feature, - std::string& lang, - std::string* error) const -{ - assert(cmGeneratorExpression::Find(feature) == std::string::npos); - - bool isCFeature = - std::find_if(cm::cbegin(C_FEATURES) + 1, cm::cend(C_FEATURES), - cmStrCmp(feature)) != cm::cend(C_FEATURES); - if (isCFeature) { - lang = "C"; - return true; - } - bool isCxxFeature = - std::find_if(cm::cbegin(CXX_FEATURES) + 1, cm::cend(CXX_FEATURES), - cmStrCmp(feature)) != cm::cend(CXX_FEATURES); - if (isCxxFeature) { - lang = "CXX"; - return true; - } - bool isCudaFeature = - std::find_if(cm::cbegin(CUDA_FEATURES) + 1, cm::cend(CUDA_FEATURES), - cmStrCmp(feature)) != cm::cend(CUDA_FEATURES); - if (isCudaFeature) { - lang = "CUDA"; - return true; - } - std::ostringstream e; - if (error) { - e << "specified"; - } else { - e << "Specified"; - } - e << " unknown feature \"" << feature - << "\" for " - "target \"" - << target->GetName() << "\"."; - if (error) { - *error = e.str(); - } else { - this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(), - this->Backtrace); - } - return false; -} - -const char* cmMakefile::CompileFeaturesAvailable(const std::string& lang, - std::string* error) const -{ - if (!this->GlobalGenerator->GetLanguageEnabled(lang)) { - std::ostringstream e; - if (error) { - e << "cannot"; - } else { - e << "Cannot"; - } - e << " use features from non-enabled language " << lang; - if (error) { - *error = e.str(); - } else { - this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(), - this->Backtrace); - } - return nullptr; - } - - const char* featuresKnown = - this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES"); - - if (!featuresKnown || !*featuresKnown) { - std::ostringstream e; - if (error) { - e << "no"; - } else { - e << "No"; - } - e << " known features for " << lang << " compiler\n\"" - << this->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID") - << "\"\nversion " - << this->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_VERSION") << "."; - if (error) { - *error = e.str(); - } else { - this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(), - this->Backtrace); - } - return nullptr; - } - return featuresKnown; -} - -bool cmMakefile::HaveStandardAvailable(cmTarget const* target, - std::string const& lang, - const std::string& feature) const -{ - if (lang == "C" || lang == "OBJC") { - return this->HaveCStandardAvailable(target, feature, lang); - } - if (lang == "CUDA") { - return this->HaveCudaStandardAvailable(target, feature, lang); - } - return this->HaveCxxStandardAvailable(target, feature, lang); -} - -bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const -{ - cmProp defaultCStandard = - this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); - if (!defaultCStandard) { - this->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("CMAKE_", lang, - "_STANDARD_DEFAULT is not set. COMPILE_FEATURES support " - "not fully configured for this compiler.")); - // Return true so the caller does not try to lookup the default standard. - return true; - } - if (std::find_if(cm::cbegin(C_STANDARDS), 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, "\"."); - this->IssueMessage(MessageType::INTERNAL_ERROR, e); - return false; - } - - bool needC90 = false; - bool needC99 = false; - bool needC11 = false; - - this->CheckNeededCLanguage(feature, lang, needC90, needC99, needC11); - - 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)) { - const std::string e = cmStrCat( - "The ", lang, "_STANDARD property on target \"", target->GetName(), - "\" 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)) - : cm::cend(C_STANDARDS); - - if (needC11 && existingCStandard && - existingCIt < std::find_if(cm::cbegin(C_STANDARDS), - cm::cend(C_STANDARDS), cmStrCmp("11"))) { - return false; - } - if (needC99 && existingCStandard && - existingCIt < std::find_if(cm::cbegin(C_STANDARDS), - cm::cend(C_STANDARDS), cmStrCmp("99"))) { - return false; - } - if (needC90 && existingCStandard && - existingCIt < std::find_if(cm::cbegin(C_STANDARDS), - cm::cend(C_STANDARDS), cmStrCmp("90"))) { - return false; - } - return true; -} - -bool cmMakefile::IsLaterStandard(std::string const& lang, - std::string const& lhs, - std::string const& rhs) -{ - if (lang == "C" || lang == "OBJC") { - const char* const* rhsIt = std::find_if( - cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), cmStrCmp(rhs)); - - return std::find_if(rhsIt, cm::cend(C_STANDARDS), cmStrCmp(lhs)) != - cm::cend(C_STANDARDS); - } - if (lang == "CUDA") { - const char* const* rhsIt = std::find_if( - cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), cmStrCmp(rhs)); - - return std::find_if(rhsIt, cm::cend(CUDA_STANDARDS), cmStrCmp(lhs)) != - cm::cend(CUDA_STANDARDS); - } - - const char* const* rhsIt = std::find_if( - cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(rhs)); - - return std::find_if(rhsIt, cm::cend(CXX_STANDARDS), cmStrCmp(lhs)) != - cm::cend(CXX_STANDARDS); -} - -bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const -{ - cmProp defaultCxxStandard = - this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); - if (!defaultCxxStandard) { - this->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("CMAKE_", lang, - "_STANDARD_DEFAULT is not set. COMPILE_FEATURES support " - "not fully configured for this compiler.")); - // Return true so the caller does not try to lookup the default standard. - return true; - } - if (std::find_if(cm::cbegin(CXX_STANDARDS), 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, "\"."); - this->IssueMessage(MessageType::INTERNAL_ERROR, e); - return false; - } - - bool needCxx98 = false; - bool needCxx11 = false; - bool needCxx14 = false; - bool needCxx17 = false; - bool needCxx20 = false; - this->CheckNeededCxxLanguage(feature, lang, needCxx98, needCxx11, needCxx14, - needCxx17, needCxx20); - - cmProp existingCxxStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); - if (!existingCxxStandard) { - existingCxxStandard = defaultCxxStandard; - } - - const char* const* existingCxxLevel = - std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), - 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, "\"."); - this->IssueMessage(MessageType::FATAL_ERROR, e); - return false; - } - - /* clang-format off */ - const char* const* needCxxLevel = - needCxx20 ? &CXX_STANDARDS[4] - : needCxx17 ? &CXX_STANDARDS[3] - : needCxx14 ? &CXX_STANDARDS[2] - : needCxx11 ? &CXX_STANDARDS[1] - : needCxx98 ? &CXX_STANDARDS[0] - : nullptr; - /* clang-format on */ - - return !needCxxLevel || needCxxLevel <= existingCxxLevel; -} - -void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, - std::string const& lang, - bool& needCxx98, bool& needCxx11, - bool& needCxx14, bool& needCxx17, - bool& needCxx20) const -{ - if (const char* propCxx98 = - this->GetDefinition(cmStrCat("CMAKE_", lang, "98_COMPILE_FEATURES"))) { - std::vector<std::string> props = cmExpandedList(propCxx98); - 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 = cm::contains(props, feature); - } - if (const char* propCxx14 = - this->GetDefinition(cmStrCat("CMAKE_", lang, "14_COMPILE_FEATURES"))) { - std::vector<std::string> props = cmExpandedList(propCxx14); - 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 = cm::contains(props, feature); - } - if (const char* propCxx20 = - this->GetDefinition(cmStrCat("CMAKE_", lang, "20_COMPILE_FEATURES"))) { - std::vector<std::string> props = cmExpandedList(propCxx20); - needCxx20 = cm::contains(props, feature); - } -} - -bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, - const std::string& feature, - std::string const& lang, - std::string* error) const -{ - bool needCxx98 = false; - bool needCxx11 = false; - bool needCxx14 = false; - bool needCxx17 = false; - bool needCxx20 = false; - - this->CheckNeededCxxLanguage(feature, lang, needCxx98, needCxx11, needCxx14, - needCxx17, needCxx20); - - cmProp existingCxxStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); - if (existingCxxStandard == nullptr) { - cmProp defaultCxxStandard = - this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); - if (defaultCxxStandard && !defaultCxxStandard->empty()) { - existingCxxStandard = defaultCxxStandard; - } - } - const char* const* existingCxxLevel = nullptr; - if (existingCxxStandard) { - existingCxxLevel = - std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), - 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, "\"."); - if (error) { - *error = e; - } else { - this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, - this->Backtrace); - } - return false; - } - } - - /* clang-format off */ - const char* const* needCxxLevel = - needCxx20 ? &CXX_STANDARDS[4] - : needCxx17 ? &CXX_STANDARDS[3] - : needCxx14 ? &CXX_STANDARDS[2] - : needCxx11 ? &CXX_STANDARDS[1] - : needCxx98 ? &CXX_STANDARDS[0] - : nullptr; - /* clang-format on */ - - if (needCxxLevel) { - // Ensure the C++ language level is high enough to support - // the needed C++ features. - if (!existingCxxLevel || existingCxxLevel < needCxxLevel) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), *needCxxLevel); - } - } - - return true; -} - -bool cmMakefile::HaveCudaStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const -{ - cmProp defaultCudaStandard = - this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); - if (!defaultCudaStandard) { - this->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("CMAKE_", lang, - "_STANDARD_DEFAULT is not set. COMPILE_FEATURES support " - "not fully configured for this compiler.")); - // Return true so the caller does not try to lookup the default standard. - return true; - } - if (std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), - cmStrCmp(*defaultCudaStandard)) == - cm::cend(CUDA_STANDARDS)) { - const std::string e = - cmStrCat("The CMAKE_", lang, "_STANDARD_DEFAULT variable contains an ", - "invalid value: \"", *defaultCudaStandard, "\"."); - this->IssueMessage(MessageType::INTERNAL_ERROR, e); - return false; - } - - bool needCuda03 = false; - bool needCuda11 = false; - bool needCuda14 = false; - bool needCuda17 = false; - bool needCuda20 = false; - this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11, - needCuda14, needCuda17, needCuda20); - - cmProp existingCudaStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); - if (!existingCudaStandard) { - existingCudaStandard = defaultCudaStandard; - } - - const char* const* existingCudaLevel = - std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), - cmStrCmp(*existingCudaStandard)); - if (existingCudaLevel == cm::cend(CUDA_STANDARDS)) { - const std::string e = cmStrCat( - "The ", lang, "_STANDARD property on target \"", target->GetName(), - "\" contained an invalid value: \"", *existingCudaStandard, "\"."); - this->IssueMessage(MessageType::FATAL_ERROR, e); - return false; - } - - /* clang-format off */ - const char* const* needCudaLevel = - needCuda20 ? &CUDA_STANDARDS[4] - : needCuda17 ? &CUDA_STANDARDS[3] - : needCuda14 ? &CUDA_STANDARDS[2] - : needCuda11 ? &CUDA_STANDARDS[1] - : needCuda03 ? &CUDA_STANDARDS[0] - : nullptr; - /* clang-format on */ - - return !needCudaLevel || needCudaLevel <= existingCudaLevel; -} - -void cmMakefile::CheckNeededCudaLanguage(const std::string& feature, - std::string const& lang, - bool& needCuda03, bool& needCuda11, - bool& needCuda14, bool& needCuda17, - bool& needCuda20) const -{ - if (const char* propCuda03 = - this->GetDefinition(cmStrCat("CMAKE_", lang, "03_COMPILE_FEATURES"))) { - std::vector<std::string> props = cmExpandedList(propCuda03); - needCuda03 = cm::contains(props, feature); - } - if (const char* propCuda11 = - this->GetDefinition(cmStrCat("CMAKE_", lang, "11_COMPILE_FEATURES"))) { - std::vector<std::string> props = cmExpandedList(propCuda11); - 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 = cm::contains(props, feature); - } - if (const char* propCuda17 = - this->GetDefinition(cmStrCat("CMAKE_", lang, "17_COMPILE_FEATURES"))) { - std::vector<std::string> props = cmExpandedList(propCuda17); - 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 = cm::contains(props, feature); - } -} - -bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target, - const std::string& feature, - std::string const& lang, - std::string* error) const -{ - bool needCuda03 = false; - bool needCuda11 = false; - bool needCuda14 = false; - bool needCuda17 = false; - bool needCuda20 = false; - - this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11, - needCuda14, needCuda17, needCuda20); - - cmProp existingCudaStandard = - target->GetProperty(cmStrCat(lang, "_STANDARD")); - if (existingCudaStandard == nullptr) { - cmProp defaultCudaStandard = - this->GetDef(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); - if (defaultCudaStandard && !defaultCudaStandard->empty()) { - existingCudaStandard = defaultCudaStandard; - } - } - const char* const* existingCudaLevel = nullptr; - if (existingCudaStandard) { - existingCudaLevel = - std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), - cmStrCmp(*existingCudaStandard)); - if (existingCudaLevel == cm::cend(CUDA_STANDARDS)) { - const std::string e = cmStrCat( - "The ", lang, "_STANDARD property on target \"", target->GetName(), - "\" contained an invalid value: \"", *existingCudaStandard, "\"."); - if (error) { - *error = e; - } else { - this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, - this->Backtrace); - } - return false; - } - } - - /* clang-format off */ - const char* const* needCudaLevel = - needCuda20 ? &CUDA_STANDARDS[4] - : needCuda17 ? &CUDA_STANDARDS[3] - : needCuda14 ? &CUDA_STANDARDS[2] - : needCuda11 ? &CUDA_STANDARDS[1] - : needCuda03 ? &CUDA_STANDARDS[0] - : nullptr; - /* clang-format on */ - - if (needCudaLevel) { - // Ensure the CUDA language level is high enough to support - // the needed CUDA features. - if (!existingCudaLevel || existingCudaLevel < needCudaLevel) { - target->SetProperty("CUDA_STANDARD", *needCudaLevel); - } - } - - return true; -} - -void cmMakefile::CheckNeededCLanguage(const std::string& feature, - std::string const& lang, bool& needC90, - bool& needC99, bool& needC11) const -{ - if (const char* propC90 = - this->GetDefinition(cmStrCat("CMAKE_", lang, "90_COMPILE_FEATURES"))) { - std::vector<std::string> props = cmExpandedList(propC90); - 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 = cm::contains(props, feature); - } - if (const char* propC11 = - this->GetDefinition(cmStrCat("CMAKE_", lang, "11_COMPILE_FEATURES"))) { - std::vector<std::string> props = cmExpandedList(propC11); - needC11 = cm::contains(props, feature); - } -} - -bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, - const std::string& feature, - std::string const& lang, - std::string* error) const -{ - bool needC90 = false; - bool needC99 = false; - bool needC11 = false; - - this->CheckNeededCLanguage(feature, lang, needC90, needC99, needC11); - - cmProp existingCStandard = target->GetProperty(cmStrCat(lang, "_STANDARD")); - if (existingCStandard == nullptr) { - 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)) { - const std::string e = cmStrCat( - "The ", lang, "_STANDARD property on target \"", target->GetName(), - "\" contained an invalid value: \"", *existingCStandard, "\"."); - if (error) { - *error = e; - } else { - this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, - this->Backtrace); - } - return false; - } - } - const char* const* existingCIt = existingCStandard - ? std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), - cmStrCmp(*existingCStandard)) - : cm::cend(C_STANDARDS); - - bool setC90 = needC90 && !existingCStandard; - bool setC99 = needC99 && !existingCStandard; - bool setC11 = needC11 && !existingCStandard; - - if (needC11 && existingCStandard && - existingCIt < std::find_if(cm::cbegin(C_STANDARDS), - cm::cend(C_STANDARDS), cmStrCmp("11"))) { - setC11 = true; - } else if (needC99 && existingCStandard && - existingCIt < std::find_if(cm::cbegin(C_STANDARDS), - cm::cend(C_STANDARDS), - cmStrCmp("99"))) { - setC99 = true; - } else if (needC90 && existingCStandard && - existingCIt < std::find_if(cm::cbegin(C_STANDARDS), - cm::cend(C_STANDARDS), - cmStrCmp("90"))) { - setC90 = true; - } - - if (setC11) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), "11"); - } else if (setC99) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), "99"); - } else if (setC90) { - target->SetProperty(cmStrCat(lang, "_STANDARD"), "90"); - } - return true; -} - cmMakefile::FunctionPushPop::FunctionPushPop(cmMakefile* mf, const std::string& fileName, cmPolicies::PolicyMap const& pm) diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 45d7109..80d80d3 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -342,12 +342,19 @@ public: */ void SetProjectName(std::string const& name); - /** Get the configurations to be generated. */ - std::string GetConfigurations(std::vector<std::string>& configs, - bool single = true) const; + /* Get the default configuration */ + std::string GetDefaultConfiguration() const; + + enum GeneratorConfigQuery + { + IncludeEmptyConfig, // Include "" aka noconfig + ExcludeEmptyConfig, // Exclude "" aka noconfig + OnlyMultiConfig, + }; /** Get the configurations for dependency checking. */ - std::vector<std::string> GetGeneratorConfigs() const; + std::vector<std::string> GetGeneratorConfigs( + GeneratorConfigQuery mode) const; /** * Set the name of the library. @@ -686,6 +693,7 @@ public: */ int ConfigureFile(const std::string& infile, const std::string& outfile, bool copyonly, bool atOnly, bool escapeQuotes, + bool use_source_permissions, cmNewLineStyle = cmNewLineStyle()); /** @@ -925,21 +933,6 @@ public: bool PolicyOptionalWarningEnabled(std::string const& var); - bool AddRequiredTargetFeature(cmTarget* target, const std::string& feature, - std::string* error = nullptr) const; - - bool CompileFeatureKnown(cmTarget const* target, const std::string& feature, - std::string& lang, std::string* error) const; - - const char* CompileFeaturesAvailable(const std::string& lang, - std::string* error) const; - - bool HaveStandardAvailable(cmTarget const* target, std::string const& lang, - const std::string& feature) const; - - bool IsLaterStandard(std::string const& lang, std::string const& lhs, - std::string const& rhs); - void PushLoopBlock(); void PopLoopBlock(); bool IsLoopBlock() const; @@ -985,9 +978,6 @@ protected: // add link libraries and directories to the target void AddGlobalLinkInformation(cmTarget& target); - // Check for a an unused variable - void LogUnused(const char* reason, const std::string& name) const; - mutable std::set<cmListFileContext> CMP0054ReportedIds; // libraries, classes, and executables @@ -1162,44 +1152,6 @@ private: */ bool MightHaveCustomCommand(const std::string& name) const; - bool AddRequiredTargetCFeature(cmTarget* target, const std::string& feature, - std::string const& lang, - std::string* error = nullptr) const; - bool AddRequiredTargetCxxFeature(cmTarget* target, - const std::string& feature, - std::string const& lang, - std::string* error = nullptr) const; - bool AddRequiredTargetCudaFeature(cmTarget* target, - const std::string& feature, - std::string const& lang, - std::string* error = nullptr) const; - - void CheckNeededCLanguage(const std::string& feature, - std::string const& lang, bool& needC90, - bool& needC99, bool& needC11) const; - void CheckNeededCxxLanguage(const std::string& feature, - std::string const& lang, bool& needCxx98, - bool& needCxx11, bool& needCxx14, - bool& needCxx17, bool& needCxx20) const; - void CheckNeededCudaLanguage(const std::string& feature, - std::string const& lang, bool& needCuda03, - bool& needCuda11, bool& needCuda14, - bool& needCuda17, bool& needCuda20) const; - - bool HaveCStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const; - bool HaveCxxStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const; - bool HaveCudaStandardAvailable(cmTarget const* target, - const std::string& feature, - std::string const& lang) const; - - void CheckForUnusedVariables() const; - - // Unused variable flags - bool WarnUnused; bool CheckSystemVars; bool CheckCMP0000; std::set<std::string> WarnedCMP0074; diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 446f225..bc288ac 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -218,7 +218,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( const char* val = this->LocalGenerator->GetRuleLauncher( this->GeneratorTarget, "RULE_LAUNCH_LINK"); - if (val && *val) { + if (cmNonempty(val)) { launcher = cmStrCat(val, ' '); } @@ -583,7 +583,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) const char* val = this->LocalGenerator->GetRuleLauncher( this->GeneratorTarget, "RULE_LAUNCH_LINK"); - if (val && *val) { + if (cmNonempty(val)) { launcher = cmStrCat(val, ' '); } diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 5809b4a..1c25fc4 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -356,7 +356,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( std::string launcher; const char* val = this->LocalGenerator->GetRuleLauncher( this->GeneratorTarget, "RULE_LAUNCH_LINK"); - if (val && *val) { + if (cmNonempty(val)) { launcher = cmStrCat(val, ' '); } @@ -809,7 +809,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( std::string launcher; const char* val = this->LocalGenerator->GetRuleLauncher( this->GeneratorTarget, "RULE_LAUNCH_LINK"); - if (val && *val) { + if (cmNonempty(val)) { launcher = cmStrCat(val, ' '); } diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 8396fa3..fae1d76 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -71,6 +71,7 @@ std::unique_ptr<cmMakefileTargetGenerator> cmMakefileTargetGenerator::New( case cmStateEnums::OBJECT_LIBRARY: result = cm::make_unique<cmMakefileLibraryTargetGenerator>(tgt); break; + case cmStateEnums::INTERFACE_LIBRARY: case cmStateEnums::UTILITY: result = cm::make_unique<cmMakefileUtilityTargetGenerator>(tgt); break; @@ -197,8 +198,7 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() } // add custom commands to the clean rules? - cmProp clean_no_custom = this->Makefile->GetProperty("CLEAN_NO_CUSTOM"); - bool clean = clean_no_custom ? cmIsOff(*clean_no_custom) : true; + bool clean = cmIsOff(this->Makefile->GetProperty("CLEAN_NO_CUSTOM")); // First generate the object rule files. Save a list of all object // files for this target. @@ -532,6 +532,13 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // Build the set of compiler flags. std::string flags; + // explicitly add the explicit language flag before any other flag + // this way backwards compatibility with user flags is maintained + if (source.GetProperty("LANGUAGE")) { + this->LocalGenerator->AppendFeatureOptions(flags, lang, + "EXPLICIT_LANGUAGE"); + } + // Add language-specific flags. std::string langFlags = cmStrCat("$(", lang, "_FLAGS", filterArch, ")"); this->LocalGenerator->AppendFlags(flags, langFlags); @@ -800,7 +807,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( lang == "OBJC" || lang == "OBJCXX")) { std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); - if (clauncher && !clauncher->empty()) { + if (cmNonempty(clauncher)) { compilerLauncher = *clauncher; } } @@ -815,8 +822,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( cmProp cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); std::string const cppcheck_prop = lang + "_CPPCHECK"; cmProp cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); - if ((iwyu && !iwyu->empty()) || (tidy && !tidy->empty()) || - (cpplint && !cpplint->empty()) || (cppcheck && !cppcheck->empty())) { + if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) || + cmNonempty(cppcheck)) { std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_co_compile"; if (!compilerLauncher.empty()) { // In __run_co_compile case the launcher command is supplied @@ -825,30 +832,30 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher); compilerLauncher.clear(); } - if (iwyu && !iwyu->empty()) { + if (cmNonempty(iwyu)) { run_iwyu += " --iwyu="; run_iwyu += this->LocalGenerator->EscapeForShell(*iwyu); } - if (tidy && !tidy->empty()) { + if (cmNonempty(tidy)) { run_iwyu += " --tidy="; const char* driverMode = this->Makefile->GetDefinition( "CMAKE_" + lang + "_CLANG_TIDY_DRIVER_MODE"); - if (!(driverMode && *driverMode)) { + if (!cmNonempty(driverMode)) { driverMode = lang == "C" ? "gcc" : "g++"; } run_iwyu += this->LocalGenerator->EscapeForShell( cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode)); } - if (cpplint && !cpplint->empty()) { + if (cmNonempty(cpplint)) { run_iwyu += " --cpplint="; run_iwyu += this->LocalGenerator->EscapeForShell(*cpplint); } - if (cppcheck && !cppcheck->empty()) { + if (cmNonempty(cppcheck)) { run_iwyu += " --cppcheck="; run_iwyu += this->LocalGenerator->EscapeForShell(*cppcheck); } - if ((tidy && !tidy->empty()) || (cpplint && !cpplint->empty()) || - (cppcheck && !cppcheck->empty())) { + if (cmNonempty(tidy) || (cmNonempty(cpplint)) || + (cmNonempty(cppcheck))) { run_iwyu += " --source="; run_iwyu += sourceFile; } @@ -875,7 +882,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( { const char* val = this->LocalGenerator->GetRuleLauncher( this->GeneratorTarget, "RULE_LAUNCH_COMPILE"); - if (val && *val) { + if (cmNonempty(val)) { launcher = cmStrCat(val, ' '); } } @@ -1851,7 +1858,7 @@ void cmMakefileTargetGenerator::GenDefFile( this->LocalGenerator->GetCurrentBinaryDirectory(), objlist_file), cmOutputConverter::SHELL); const char* nm_executable = this->Makefile->GetDefinition("CMAKE_NM"); - if (nm_executable && *nm_executable) { + if (cmNonempty(nm_executable)) { cmd += " --nm="; cmd += this->LocalCommonGenerator->ConvertToOutputFormat( nm_executable, cmOutputConverter::SHELL); diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 32ab9f8..bde5ee7 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -239,7 +239,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule( std::string launcher; const char* val = this->GetLocalGenerator()->GetRuleLauncher( this->GetGeneratorTarget(), "RULE_LAUNCH_LINK"); - if (val && *val) { + if (cmNonempty(val)) { launcher = cmStrCat(val, ' '); } @@ -376,7 +376,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, std::string launcher; const char* val = this->GetLocalGenerator()->GetRuleLauncher( this->GetGeneratorTarget(), "RULE_LAUNCH_LINK"); - if (val && *val) { + if (cmNonempty(val)) { launcher = cmStrCat(val, ' '); } @@ -739,7 +739,8 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement( // Gather order-only dependencies. this->GetLocalGenerator()->AppendTargetDepends( - this->GetGeneratorTarget(), build.OrderOnlyDeps, config, config); + this->GetGeneratorTarget(), build.OrderOnlyDeps, config, config, + DependOnTargetArtifact); // Write the build statement for this target. bool usedResponseFile = false; @@ -1091,7 +1092,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( obj_list_file, cmOutputConverter::SHELL); const char* nm_executable = GetMakefile()->GetDefinition("CMAKE_NM"); - if (nm_executable && *nm_executable) { + if (cmNonempty(nm_executable)) { cmd += " --nm="; cmd += this->LocalCommonGenerator->ConvertToOutputFormat( nm_executable, cmOutputConverter::SHELL); @@ -1160,8 +1161,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp")); // Gather order-only dependencies. - this->GetLocalGenerator()->AppendTargetDepends(gt, linkBuild.OrderOnlyDeps, - config, fileConfig); + this->GetLocalGenerator()->AppendTargetDepends( + gt, linkBuild.OrderOnlyDeps, config, fileConfig, DependOnTargetArtifact); // Add order-only dependencies on versioning symlinks of shared libs we link. if (!this->GeneratorTarget->IsDLLPlatform()) { diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index d406c99..57f526e 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -51,6 +51,7 @@ std::unique_ptr<cmNinjaTargetGenerator> cmNinjaTargetGenerator::New( return cm::make_unique<cmNinjaNormalTargetGenerator>(target); case cmStateEnums::UTILITY: + case cmStateEnums::INTERFACE_LIBRARY: case cmStateEnums::GLOBAL_TARGET: return cm::make_unique<cmNinjaUtilityTargetGenerator>(target); @@ -65,7 +66,8 @@ cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmGeneratorTarget* target) , LocalGenerator( static_cast<cmLocalNinjaGenerator*>(target->GetLocalGenerator())) { - for (auto const& fileConfig : target->Makefile->GetGeneratorConfigs()) { + for (auto const& fileConfig : + target->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) { this->Configs[fileConfig].MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this, fileConfig); } @@ -188,7 +190,16 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( } } - std::string flags = this->GetFlags(language, config, filterArch); + std::string flags; + // explicitly add the explicit language flag before any other flag + // this way backwards compatibility with user flags is maintained + if (source->GetProperty("LANGUAGE")) { + this->LocalGenerator->AppendFeatureOptions(flags, language, + "EXPLICIT_LANGUAGE"); + flags += " "; + } + + flags += this->GetFlags(language, config, filterArch); // Add Fortran format flags. if (language == "Fortran") { @@ -652,7 +663,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, std::string launcher; const char* val = this->GetLocalGenerator()->GetRuleLauncher( this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE"); - if (val && *val) { + if (cmNonempty(val)) { launcher = cmStrCat(val, ' '); } @@ -803,7 +814,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, lang == "OBJC" || lang == "OBJCXX")) { std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER"); cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); - if (clauncher && !clauncher->empty()) { + if (cmNonempty(clauncher)) { compilerLauncher = *clauncher; } } @@ -818,8 +829,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, 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())) { + if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) || + cmNonempty(cppcheck)) { std::string run_iwyu = cmStrCat(cmakeCmd, " -E __run_co_compile"); if (!compilerLauncher.empty()) { // In __run_co_compile case the launcher command is supplied @@ -829,31 +840,30 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, this->LocalGenerator->EscapeForShell(compilerLauncher)); compilerLauncher.clear(); } - if (iwyu && !iwyu->empty()) { + if (cmNonempty(iwyu)) { run_iwyu += cmStrCat(" --iwyu=", this->GetLocalGenerator()->EscapeForShell(*iwyu)); } - if (tidy && !tidy->empty()) { + if (cmNonempty(tidy)) { run_iwyu += " --tidy="; const char* driverMode = this->Makefile->GetDefinition( cmStrCat("CMAKE_", lang, "_CLANG_TIDY_DRIVER_MODE")); - if (!(driverMode && *driverMode)) { + if (!cmNonempty(driverMode)) { driverMode = lang == "C" ? "gcc" : "g++"; } run_iwyu += this->GetLocalGenerator()->EscapeForShell( cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode)); } - if (cpplint && !cpplint->empty()) { + if (cmNonempty(cpplint)) { run_iwyu += cmStrCat( " --cpplint=", this->GetLocalGenerator()->EscapeForShell(*cpplint)); } - if (cppcheck && !cppcheck->empty()) { + if (cmNonempty(cppcheck)) { run_iwyu += cmStrCat(" --cppcheck=", this->GetLocalGenerator()->EscapeForShell(*cppcheck)); } - if ((tidy && !tidy->empty()) || (cpplint && !cpplint->empty()) || - (cppcheck && !cppcheck->empty())) { + if (cmNonempty(tidy) || cmNonempty(cpplint) || cmNonempty(cppcheck)) { run_iwyu += " --source=$in"; } run_iwyu += " -- "; diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index 8d863c3..9508bb9 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -101,7 +101,8 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config) lg->AppendTargetOutputs(genTarget, gg->GetByproductsForCleanTarget(), config); } - lg->AppendTargetDepends(genTarget, deps, config, config); + lg->AppendTargetDepends(genTarget, deps, config, config, + DependOnTargetArtifact); if (commands.empty()) { phonyBuild.Comment = "Utility command for " + this->GetTargetName(); diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index dea3f8a..01e8c04 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -7,9 +7,11 @@ #include <sstream> #include <vector> +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmState.h" +#include "cmStateSnapshot.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -157,7 +159,8 @@ static bool GetPolicyDefault(cmMakefile* mf, std::string const& policy, bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, std::string const& version_min, - std::string const& version_max) + std::string const& version_max, + WarnCompat warnCompat) { // Parse components of the minimum version. unsigned int minMajor = 2; @@ -244,13 +247,34 @@ bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, polPatch = maxPatch; } - return cmPolicies::ApplyPolicyVersion(mf, polMajor, polMinor, polPatch); + return cmPolicies::ApplyPolicyVersion(mf, polMajor, polMinor, polPatch, + warnCompat); } bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer, unsigned int minorVer, - unsigned int patchVer) + unsigned int patchVer, + WarnCompat warnCompat) { + // Warn about policy versions for which support will be removed. + if (warnCompat == WarnCompat::On && + (majorVer < 2 || (majorVer == 2 && minorVer < 8) || + (majorVer == 2 && minorVer == 8 && patchVer < 12)) && + // Avoid warning on calls generated by install(EXPORT) + // in CMake versions prior to 3.18. + !(majorVer == 2 && minorVer == 6 && patchVer == 0 && + mf->GetStateSnapshot().CanPopPolicyScope() && + cmSystemTools::Strucmp(mf->GetBacktrace().Top().Name.c_str(), + "cmake_policy") == 0)) { + mf->IssueMessage( + MessageType::DEPRECATION_WARNING, + "Compatibility with CMake < 2.8.12 will be removed from " + "a future version of CMake.\n" + "Update the VERSION argument <min> value or use a ...<max> suffix " + "to tell CMake that the project does not need compatibility with " + "older versions."); + } + // now loop over all the policies and set them as appropriate std::vector<cmPolicies::PolicyID> ancientPolicies; for (PolicyID pid = cmPolicies::CMP0000; pid != cmPolicies::CMPCOUNT; diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index a82f421..0c00ffb 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -320,7 +320,13 @@ class cmMakefile; 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) + 3, 18, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0109, \ + "find_program() requires permission to execute but not to read.", 3, \ + 19, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0110, \ + "add_test() supports arbitrary characters in test names.", 3, 19, 0, \ + cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ @@ -396,12 +402,20 @@ public: //! Get the default status for a policy static cmPolicies::PolicyStatus GetPolicyStatus(cmPolicies::PolicyID id); + enum class WarnCompat + { + Off, + On + }; + //! Set a policy level for this listfile static bool ApplyPolicyVersion(cmMakefile* mf, std::string const& version_min, - std::string const& version_max); + std::string const& version_max, + WarnCompat warnCompat); static bool ApplyPolicyVersion(cmMakefile* mf, unsigned int majorVer, - unsigned int minorVer, unsigned int patchVer); + unsigned int minorVer, unsigned int patchVer, + WarnCompat warnCompat); //! return a warning string for a given policy static std::string GetPolicyWarning(cmPolicies::PolicyID id); diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index 2ec66d9..bb6db92 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -303,7 +303,7 @@ bool cmProjectCommand(std::vector<std::string> const& args, std::string vw; for (std::string const& i : vv) { const char* const v = mf.GetDefinition(i); - if (v && *v) { + if (cmNonempty(v)) { if (cmp0048 == cmPolicies::WARN) { if (!injectedProjectCommand) { vw += "\n "; diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx index 3d4f5d7..fac2bbf 100644 --- a/Source/cmQtAutoGenGlobalInitializer.cxx +++ b/Source/cmQtAutoGenGlobalInitializer.cxx @@ -50,7 +50,7 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( { cmMakefile* makefile = localGen->GetMakefile(); // Detect global autogen target name - if (cmIsOn(makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET"))) { + if (makefile->IsOn("CMAKE_GLOBAL_AUTOGEN_TARGET")) { std::string targetName = makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET_NAME"); if (targetName.empty()) { @@ -61,7 +61,7 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( } // Detect global autorcc target name - if (cmIsOn(makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET"))) { + if (makefile->IsOn("CMAKE_GLOBAL_AUTORCC_TARGET")) { std::string targetName = makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET_NAME"); if (targetName.empty()) { diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 1132852..06957b0 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -315,10 +315,9 @@ bool cmQtAutoGenInitializer::InitCustomTargets() { // Configurations this->MultiConfig = this->GlobalGen->IsMultiConfig(); - this->ConfigDefault = this->Makefile->GetConfigurations(this->ConfigsList); - if (this->ConfigsList.empty()) { - this->ConfigsList.push_back(this->ConfigDefault); - } + this->ConfigDefault = this->Makefile->GetDefaultConfiguration(); + this->ConfigsList = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); // Verbosity { @@ -490,7 +489,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets() if (this->Moc.Enabled) { // Path prefix - if (cmIsOn(this->GenTarget->GetSafeProperty("AUTOMOC_PATH_PREFIX"))) { + if (cmIsOn(this->GenTarget->GetProperty("AUTOMOC_PATH_PREFIX"))) { this->Moc.PathPrefix = true; } @@ -789,9 +788,9 @@ bool cmQtAutoGenInitializer::InitScanFiles() // Register files that will be scanned by moc or uic if (this->MocOrUicEnabled()) { - if (cm->IsHeaderExtension(extLower)) { + if (cm->IsAHeaderExtension(extLower)) { addMUHeader(makeMUFile(sf, fullPath, true), extLower); - } else if (cm->IsSourceExtension(extLower)) { + } else if (cm->IsACLikeSourceExtension(extLower)) { addMUSource(makeMUFile(sf, fullPath, true)); } } @@ -863,7 +862,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() if (sf != nullptr) { auto eMuf = makeMUFile(sf, fullPath, true); - // Ony process moc/uic when the parent is processed as well + // Only process moc/uic when the parent is processed as well if (!muf.MocIt) { eMuf->MocIt = false; } @@ -895,14 +894,14 @@ bool cmQtAutoGenInitializer::InitScanFiles() std::string const& extLower = cmSystemTools::LowerCase(sf->GetExtension()); - if (cm->IsHeaderExtension(extLower)) { + if (cm->IsAHeaderExtension(extLower)) { 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)) { + } else if (cm->IsACLikeSourceExtension(extLower)) { if (!cm::contains(this->AutogenTarget.Sources, sf.get())) { auto muf = makeMUFile(sf.get(), fullPath, false); if (muf->SkipMoc || muf->SkipUic) { @@ -1654,7 +1653,7 @@ void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName, }; for (std::string const& prop : props) { cmProp propName = this->Makefile->GetState()->GetGlobalProperty(prop); - if (propName && !propName->empty()) { + if (cmNonempty(propName)) { groupName = *propName; property = prop; break; diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index 254131b..4ff81c1 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -261,7 +261,7 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( this->VariableMappings["CMAKE_" + compIt->second + "_COMPILE_OPTIONS_SYSROOT"]; - // if there is a required first argument to the compiler add it + // if there are required arguments to the compiler add it // to the compiler string if (!compilerArg1.empty()) { ret += " "; diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx index 766d347..eb8fcaf 100644 --- a/Source/cmSearchPath.cxx +++ b/Source/cmSearchPath.cxx @@ -180,7 +180,7 @@ void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths, if (subdir == "include" || subdir == "lib") { const char* arch = this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE"); - if (arch && *arch) { + if (cmNonempty(arch)) { if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") && this->FC->Makefile->IsDefinitionSet( "CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) { diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index 4f7131f..e586fd9 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -136,6 +136,7 @@ bool cmServerProtocol::Activate(cmServer* server, this->m_Server = server; this->m_CMakeInstance = cm::make_unique<cmake>(cmake::RoleProject, cmState::Project); + this->m_WarnUnused = false; const bool result = this->DoActivate(request, errorMessage); if (!result) { this->m_CMakeInstance = nullptr; @@ -636,7 +637,7 @@ cmServerResponse cmServerProtocol1::ProcessGlobalSettings( obj[kTRACE_KEY] = cm->GetTrace(); obj[kTRACE_EXPAND_KEY] = cm->GetTraceExpand(); obj[kWARN_UNINITIALIZED_KEY] = cm->GetWarnUninitialized(); - obj[kWARN_UNUSED_KEY] = cm->GetWarnUnused(); + obj[kWARN_UNUSED_KEY] = m_WarnUnused; obj[kWARN_UNUSED_CLI_KEY] = cm->GetWarnUnusedCli(); obj[kCHECK_SYSTEM_VARS_KEY] = cm->GetCheckSystemVars(); @@ -682,7 +683,7 @@ cmServerResponse cmServerProtocol1::ProcessSetGlobalSettings( setBool(request, kTRACE_EXPAND_KEY, [cm](bool e) { cm->SetTraceExpand(e); }); setBool(request, kWARN_UNINITIALIZED_KEY, [cm](bool e) { cm->SetWarnUninitialized(e); }); - setBool(request, kWARN_UNUSED_KEY, [cm](bool e) { cm->SetWarnUnused(e); }); + setBool(request, kWARN_UNUSED_KEY, [this](bool e) { m_WarnUnused = e; }); setBool(request, kWARN_UNUSED_CLI_KEY, [cm](bool e) { cm->SetWarnUnusedCli(e); }); setBool(request, kCHECK_SYSTEM_VARS_KEY, diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h index c71b7bf..6009e23 100644 --- a/Source/cmServerProtocol.h +++ b/Source/cmServerProtocol.h @@ -94,6 +94,7 @@ protected: // Implement protocol specific activation tasks here. Called from Activate(). virtual bool DoActivate(const cmServerRequest& request, std::string* errorMessage); + bool m_WarnUnused = false; // storage for legacy option private: std::unique_ptr<cmake> m_CMakeInstance; diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index f525439..ef44a57 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmSourceFile.h" -#include <array> #include <utility> #include "cmGlobalGenerator.h" @@ -130,13 +129,11 @@ bool cmSourceFile::FindFullPath(std::string* error) // Location path std::string const& lPath = this->Location.GetFullPath(); // List of extension lists - std::array<std::vector<std::string> const*, 2> const extsLists = { - { &makefile->GetCMakeInstance()->GetSourceExtensions(), - &makefile->GetCMakeInstance()->GetHeaderExtensions() } - }; + std::vector<std::string> exts = + makefile->GetCMakeInstance()->GetAllExtensions(); // Tries to find the file in a given directory - auto findInDir = [this, &extsLists, &lPath](std::string const& dir) -> bool { + auto findInDir = [this, &exts, &lPath](std::string const& dir) -> bool { // Compute full path std::string const fullPath = cmSystemTools::CollapseFullPath(lPath, dir); // Try full path @@ -145,14 +142,12 @@ bool cmSourceFile::FindFullPath(std::string* error) return true; } // Try full path with extension - for (auto& exts : extsLists) { - for (std::string const& ext : *exts) { - if (!ext.empty()) { - std::string extPath = cmStrCat(fullPath, '.', ext); - if (cmSystemTools::FileExists(extPath)) { - this->FullPath = extPath; - return true; - } + for (std::string const& ext : exts) { + if (!ext.empty()) { + std::string extPath = cmStrCat(fullPath, '.', ext); + if (cmSystemTools::FileExists(extPath)) { + this->FullPath = extPath; + return true; } } } @@ -175,11 +170,9 @@ bool cmSourceFile::FindFullPath(std::string* error) // Compose error std::string err = cmStrCat("Cannot find source file:\n ", lPath, "\nTried extensions"); - for (auto exts : extsLists) { - for (std::string const& ext : *exts) { - err += " ."; - err += ext; - } + for (std::string const& ext : exts) { + err += " ."; + err += ext; } if (error != nullptr) { *error = std::move(err); @@ -387,8 +380,7 @@ const char* cmSourceFile::GetSafeProperty(const std::string& prop) const bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const { - cmProp p = this->GetProperty(prop); - return p && cmIsOn(*p); + return cmIsOn(this->GetProperty(prop)); } void cmSourceFile::SetProperties(cmPropertyMap properties) diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx index e852c05..222bafa 100644 --- a/Source/cmSourceFileLocation.cxx +++ b/Source/cmSourceFileLocation.cxx @@ -101,7 +101,7 @@ void cmSourceFileLocation::UpdateExtension(const std::string& name) cmMakefile const* mf = this->Makefile; auto cm = mf->GetCMakeInstance(); if (!gg->GetLanguageFromExtension(ext.c_str()).empty() || - cm->IsSourceExtension(ext) || cm->IsHeaderExtension(ext)) { + cm->IsAKnownExtension(ext)) { // This is a known extension. Use the given filename with extension. this->Name = cmSystemTools::GetFilenameName(name); this->AmbiguousExtension = false; @@ -157,7 +157,7 @@ bool cmSourceFileLocation::MatchesAmbiguousExtension( 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); + return cm->IsAKnownExtension(ext); } bool cmSourceFileLocation::Matches(cmSourceFileLocation const& loc) diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx new file mode 100644 index 0000000..6dbab98 --- /dev/null +++ b/Source/cmStandardLevelResolver.cxx @@ -0,0 +1,538 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include "cmStandardLevelResolver.h" + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <sstream> +#include <stdexcept> +#include <unordered_map> +#include <utility> +#include <vector> + +#include <cm/iterator> +#include <cmext/algorithm> + +#include "cmGeneratorExpression.h" +#include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmProperty.h" +#include "cmStringAlgorithms.h" +#include "cmTarget.h" +#include "cmake.h" + +namespace { + +#define FEATURE_STRING(F) , #F +const char* const C_FEATURES[] = { nullptr FOR_EACH_C_FEATURE( + FEATURE_STRING) }; + +const char* const CXX_FEATURES[] = { nullptr FOR_EACH_CXX_FEATURE( + FEATURE_STRING) }; + +const char* const CUDA_FEATURES[] = { nullptr FOR_EACH_CUDA_FEATURE( + FEATURE_STRING) }; +#undef FEATURE_STRING + +struct StandardNeeded +{ + int index; + int value; +}; + +struct StanardLevelComputer +{ + explicit StanardLevelComputer(std::string lang, std::vector<int> levels, + std::vector<std::string> levelsStr) + : Language(std::move(lang)) + , Levels(std::move(levels)) + , LevelsAsStrings(std::move(levelsStr)) + { + assert(levels.size() == levelsStr.size()); + } + + std::string GetCompileOptionDef(cmMakefile* makefile, + cmGeneratorTarget const* target, + std::string const& config) const + { + + const auto& stds = this->Levels; + const auto& stdsStrings = this->LevelsAsStrings; + + const char* defaultStd = makefile->GetDefinition( + cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT")); + if (!cmNonempty(defaultStd)) { + // this compiler has no notion of language standard levels + return std::string{}; + } + + bool ext = true; + if (cmProp extPropValue = target->GetLanguageExtensions(this->Language)) { + if (cmIsOff(*extPropValue)) { + ext = false; + } + } + + cmProp standardProp = target->GetLanguageStandard(this->Language, config); + if (!standardProp) { + if (ext) { + // No language standard is specified and extensions are not disabled. + // Check if this compiler needs a flag to enable extensions. + return cmStrCat("CMAKE_", this->Language, "_EXTENSION_COMPILE_OPTION"); + } + return std::string{}; + } + + std::string const type = ext ? "EXTENSION" : "STANDARD"; + + if (target->GetLanguageStandardRequired(this->Language)) { + std::string option_flag = cmStrCat( + "CMAKE_", this->Language, *standardProp, "_", type, "_COMPILE_OPTION"); + + const char* opt = + target->Target->GetMakefile()->GetDefinition(option_flag); + if (!opt) { + std::ostringstream e; + e << "Target \"" << target->GetName() + << "\" requires the language " + "dialect \"" + << this->Language << *standardProp << "\" " + << (ext ? "(with compiler extensions)" : "") + << ", but CMake " + "does not know the compile flags to use to enable it."; + makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + } + return option_flag; + } + + std::string standardStr(*standardProp); + if (this->Language == "CUDA" && standardStr == "98") { + standardStr = "03"; + } + + int standardValue = -1; + int defaultValue = -1; + try { + standardValue = std::stoi(standardStr); + defaultValue = std::stoi(defaultStd); + } catch (std::invalid_argument&) { + // fall through as we want an error + // when we can't find the bad value in the `stds` vector + } + + auto stdIt = std::find(cm::cbegin(stds), cm::cend(stds), standardValue); + if (stdIt == cm::cend(stds)) { + std::string e = + cmStrCat(this->Language, "_STANDARD is set to invalid value '", + standardStr, "'"); + makefile->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, + target->GetBacktrace()); + return std::string{}; + } + + auto defaultStdIt = + std::find(cm::cbegin(stds), cm::cend(stds), defaultValue); + if (defaultStdIt == cm::cend(stds)) { + std::string e = cmStrCat("CMAKE_", this->Language, + "_STANDARD_DEFAULT is set to invalid value '", + defaultStd, "'"); + makefile->IssueMessage(MessageType::INTERNAL_ERROR, e); + return std::string{}; + } + + // If the standard requested is older than the compiler's default + // then we need to use a flag to change it. + if (stdIt <= defaultStdIt) { + auto offset = std::distance(cm::cbegin(stds), stdIt); + return cmStrCat("CMAKE_", this->Language, stdsStrings[offset], "_", type, + "_COMPILE_OPTION"); + } + + // The standard requested is at least as new as the compiler's default, + // and the standard request is not required. Decay to the newest standard + // for which a flag is defined. + for (; defaultStdIt < stdIt; --stdIt) { + auto offset = std::distance(cm::cbegin(stds), stdIt); + std::string option_flag = + cmStrCat("CMAKE_", this->Language, stdsStrings[offset], "_", type, + "_COMPILE_OPTION"); + if (target->Target->GetMakefile()->GetDefinition(option_flag)) { + return option_flag; + } + } + + return std::string{}; + } + + bool GetNewRequiredStandard(cmMakefile* makefile, + std::string const& targetName, + const std::string& feature, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error) const + { + if (currentLangStandardValue) { + newRequiredStandard = *currentLangStandardValue; + } else { + newRequiredStandard.clear(); + } + + auto needed = this->HighestStandardNeeded(makefile, feature); + + cmProp existingStandard = currentLangStandardValue; + if (existingStandard == nullptr) { + cmProp defaultStandard = makefile->GetDef( + cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT")); + if (cmNonempty(defaultStandard)) { + existingStandard = defaultStandard; + } + } + + auto existingLevelIter = cm::cend(this->Levels); + if (existingStandard) { + existingLevelIter = + std::find(cm::cbegin(this->Levels), cm::cend(this->Levels), + std::stoi(*existingStandard)); + if (existingLevelIter == cm::cend(this->Levels)) { + const std::string e = + cmStrCat("The ", this->Language, "_STANDARD property on target \"", + targetName, "\" contained an invalid value: \"", + *existingStandard, "\"."); + if (error) { + *error = e; + } else { + makefile->IssueMessage(MessageType::FATAL_ERROR, e); + } + return false; + } + } + + if (needed.index != -1) { + // Ensure the C++ language level is high enough to support + // the needed C++ features. + if (existingLevelIter == cm::cend(this->Levels) || + existingLevelIter < this->Levels.begin() + needed.index) { + newRequiredStandard = this->LevelsAsStrings[needed.index]; + } + } + + return true; + } + + bool HaveStandardAvailable(cmMakefile* makefile, + cmGeneratorTarget const* target, + std::string const& config, + std::string const& feature) const + { + cmProp defaultStandard = makefile->GetDef( + cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT")); + if (!defaultStandard) { + makefile->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("CMAKE_", this->Language, + "_STANDARD_DEFAULT is not set. COMPILE_FEATURES support " + "not fully configured for this compiler.")); + // Return true so the caller does not try to lookup the default standard. + return true; + } + // convert defaultStandard to an integer + if (std::find(cm::cbegin(this->Levels), cm::cend(this->Levels), + std::stoi(*defaultStandard)) == cm::cend(this->Levels)) { + const std::string e = cmStrCat("The CMAKE_", this->Language, + "_STANDARD_DEFAULT variable contains an " + "invalid value: \"", + *defaultStandard, "\"."); + makefile->IssueMessage(MessageType::INTERNAL_ERROR, e); + return false; + } + + cmProp existingStandard = + target->GetLanguageStandard(this->Language, config); + if (!existingStandard) { + existingStandard = defaultStandard; + } + + auto existingLevelIter = + std::find(cm::cbegin(this->Levels), cm::cend(this->Levels), + std::stoi(*existingStandard)); + if (existingLevelIter == cm::cend(this->Levels)) { + const std::string e = + cmStrCat("The ", this->Language, "_STANDARD property on target \"", + target->GetName(), "\" contained an invalid value: \"", + *existingStandard, "\"."); + makefile->IssueMessage(MessageType::FATAL_ERROR, e); + return false; + } + + auto needed = this->HighestStandardNeeded(makefile, feature); + + return (needed.index == -1) || + (this->Levels.begin() + needed.index) <= existingLevelIter; + } + + StandardNeeded HighestStandardNeeded(cmMakefile* makefile, + std::string const& feature) const + { + std::string prefix = cmStrCat("CMAKE_", this->Language); + StandardNeeded maxLevel = { -1, -1 }; + for (size_t i = 0; i < this->Levels.size(); ++i) { + if (const char* prop = makefile->GetDefinition( + cmStrCat(prefix, this->LevelsAsStrings[i], "_COMPILE_FEATURES"))) { + std::vector<std::string> props = cmExpandedList(prop); + if (cm::contains(props, feature)) { + maxLevel = { static_cast<int>(i), this->Levels[i] }; + } + } + } + return maxLevel; + } + + bool IsLaterStandard(int lhs, int rhs) const + { + auto rhsIt = + std::find(cm::cbegin(this->Levels), cm::cend(this->Levels), rhs); + + return std::find(rhsIt, cm::cend(this->Levels), lhs) != + cm::cend(this->Levels); + } + + std::string Language; + std::vector<int> Levels; + std::vector<std::string> LevelsAsStrings; +}; + +std::unordered_map<std::string, StanardLevelComputer> StandardComputerMapping = + { + { "C", + StanardLevelComputer{ "C", std::vector<int>{ 90, 99, 11 }, + std::vector<std::string>{ "90", "99", "11" } } }, + { "CXX", + StanardLevelComputer{ + "CXX", std::vector<int>{ 98, 11, 14, 17, 20 }, + std::vector<std::string>{ "98", "11", "14", "17", "20" } } }, + { "CUDA", + StanardLevelComputer{ + "CUDA", std::vector<int>{ 03, 11, 14, 17, 20 }, + std::vector<std::string>{ "03", "11", "14", "17", "20" } } }, + { "OBJC", + StanardLevelComputer{ "OBJC", std::vector<int>{ 90, 99, 11 }, + std::vector<std::string>{ "90", "99", "11" } } }, + { "OBJCXX", + StanardLevelComputer{ + "OBJCXX", std::vector<int>{ 98, 11, 14, 17, 20 }, + std::vector<std::string>{ "98", "11", "14", "17", "20" } } }, + }; +} + +std::string cmStandardLevelResolver::GetCompileOptionDef( + cmGeneratorTarget const* target, std::string const& lang, + std::string const& config) const +{ + const auto& mapping = StandardComputerMapping.find(lang); + if (mapping == cm::cend(StandardComputerMapping)) { + return std::string{}; + } + + return mapping->second.GetCompileOptionDef(this->Makefile, target, config); +} + +bool cmStandardLevelResolver::AddRequiredTargetFeature( + cmTarget* target, const std::string& feature, std::string* error) const +{ + if (cmGeneratorExpression::Find(feature) != std::string::npos) { + target->AppendProperty("COMPILE_FEATURES", feature); + return true; + } + + std::string lang; + if (!this->CheckCompileFeaturesAvailable(target->GetName(), feature, lang, + error)) { + return false; + } + + target->AppendProperty("COMPILE_FEATURES", feature); + + // FIXME: Add a policy to avoid updating the <LANG>_STANDARD target + // property due to COMPILE_FEATURES. The language standard selection + // should be done purely at generate time based on whatever the project + // code put in these properties explicitly. That is mostly true now, + // but for compatibility we need to continue updating the property here. + std::string newRequiredStandard; + bool newRequired = this->GetNewRequiredStandard( + target->GetName(), feature, + target->GetProperty(cmStrCat(lang, "_STANDARD")), newRequiredStandard, + error); + if (!newRequiredStandard.empty()) { + target->SetProperty(cmStrCat(lang, "_STANDARD"), newRequiredStandard); + } + return newRequired; +} + +bool cmStandardLevelResolver::CheckCompileFeaturesAvailable( + const std::string& targetName, const std::string& feature, std::string& lang, + std::string* error) const +{ + if (!this->CompileFeatureKnown(targetName, feature, lang, error)) { + return false; + } + + const char* features = this->CompileFeaturesAvailable(lang, error); + if (!features) { + return false; + } + + std::vector<std::string> availableFeatures = cmExpandedList(features); + if (!cm::contains(availableFeatures, feature)) { + std::ostringstream e; + e << "The compiler feature \"" << feature << "\" is not known to " << lang + << " compiler\n\"" + << this->Makefile->GetDefinition("CMAKE_" + lang + "_COMPILER_ID") + << "\"\nversion " + << this->Makefile->GetDefinition("CMAKE_" + lang + "_COMPILER_VERSION") + << "."; + if (error) { + *error = e.str(); + } else { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + } + return false; + } + + return true; +} + +bool cmStandardLevelResolver::CompileFeatureKnown( + const std::string& targetName, const std::string& feature, std::string& lang, + std::string* error) const +{ + assert(cmGeneratorExpression::Find(feature) == std::string::npos); + + bool isCFeature = + std::find_if(cm::cbegin(C_FEATURES) + 1, cm::cend(C_FEATURES), + cmStrCmp(feature)) != cm::cend(C_FEATURES); + if (isCFeature) { + lang = "C"; + return true; + } + bool isCxxFeature = + std::find_if(cm::cbegin(CXX_FEATURES) + 1, cm::cend(CXX_FEATURES), + cmStrCmp(feature)) != cm::cend(CXX_FEATURES); + if (isCxxFeature) { + lang = "CXX"; + return true; + } + bool isCudaFeature = + std::find_if(cm::cbegin(CUDA_FEATURES) + 1, cm::cend(CUDA_FEATURES), + cmStrCmp(feature)) != cm::cend(CUDA_FEATURES); + if (isCudaFeature) { + lang = "CUDA"; + return true; + } + std::ostringstream e; + if (error) { + e << "specified"; + } else { + e << "Specified"; + } + e << " unknown feature \"" << feature + << "\" for " + "target \"" + << targetName << "\"."; + if (error) { + *error = e.str(); + } else { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + } + return false; +} + +const char* cmStandardLevelResolver::CompileFeaturesAvailable( + const std::string& lang, std::string* error) const +{ + if (!this->Makefile->GetGlobalGenerator()->GetLanguageEnabled(lang)) { + std::ostringstream e; + if (error) { + e << "cannot"; + } else { + e << "Cannot"; + } + e << " use features from non-enabled language " << lang; + if (error) { + *error = e.str(); + } else { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + } + return nullptr; + } + + const char* featuresKnown = + this->Makefile->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES"); + + if (!cmNonempty(featuresKnown)) { + std::ostringstream e; + if (error) { + e << "no"; + } else { + e << "No"; + } + e << " known features for " << lang << " compiler\n\"" + << this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID") + << "\"\nversion " + << this->Makefile->GetSafeDefinition("CMAKE_" + lang + + "_COMPILER_VERSION") + << "."; + if (error) { + *error = e.str(); + } else { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + } + return nullptr; + } + return featuresKnown; +} + +bool cmStandardLevelResolver::GetNewRequiredStandard( + const std::string& targetName, const std::string& feature, + cmProp currentLangStandardValue, std::string& newRequiredStandard, + std::string* error) const +{ + std::string lang; + if (!this->CheckCompileFeaturesAvailable(targetName, feature, lang, error)) { + return false; + } + + auto mapping = StandardComputerMapping.find(lang); + if (mapping != cm::cend(StandardComputerMapping)) { + return mapping->second.GetNewRequiredStandard( + this->Makefile, targetName, feature, currentLangStandardValue, + newRequiredStandard, error); + } + return false; +} + +bool cmStandardLevelResolver::HaveStandardAvailable( + cmGeneratorTarget const* target, std::string const& lang, + std::string const& config, const std::string& feature) const +{ + auto mapping = StandardComputerMapping.find(lang); + if (mapping != cm::cend(StandardComputerMapping)) { + return mapping->second.HaveStandardAvailable(this->Makefile, target, + config, feature); + } + return false; +} + +bool cmStandardLevelResolver::IsLaterStandard(std::string const& lang, + std::string const& lhs, + std::string const& rhs) const +{ + auto mapping = StandardComputerMapping.find(lang); + if (mapping != cm::cend(StandardComputerMapping)) { + return mapping->second.IsLaterStandard(std::stoi(lhs), std::stoi(rhs)); + } + return false; +} diff --git a/Source/cmStandardLevelResolver.h b/Source/cmStandardLevelResolver.h new file mode 100644 index 0000000..959a5f9 --- /dev/null +++ b/Source/cmStandardLevelResolver.h @@ -0,0 +1,59 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmStandardLevelResolver_h +#define cmStandardLevelResolver_h + +#include <string> + +#include "cmProperty.h" + +class cmMakefile; +class cmGeneratorTarget; +class cmTarget; + +class cmStandardLevelResolver +{ + +public: + explicit cmStandardLevelResolver(cmMakefile* makefile) + : Makefile(makefile) + { + } + + std::string GetCompileOptionDef(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config) const; + + bool AddRequiredTargetFeature(cmTarget* target, const std::string& feature, + std::string* error = nullptr) const; + + bool CompileFeatureKnown(const std::string& targetName, + const std::string& feature, std::string& lang, + std::string* error) const; + + const char* CompileFeaturesAvailable(const std::string& lang, + std::string* error) const; + + bool GetNewRequiredStandard(const std::string& targetName, + const std::string& feature, + cmProp currentLangStandardValue, + std::string& newRequiredStandard, + std::string* error = nullptr) const; + + bool HaveStandardAvailable(cmGeneratorTarget const* target, + std::string const& lang, + std::string const& config, + const std::string& feature) const; + + bool IsLaterStandard(std::string const& lang, std::string const& lhs, + std::string const& rhs) const; + +private: + bool CheckCompileFeaturesAvailable(const std::string& targetName, + const std::string& feature, + std::string& lang, + std::string* error) const; + + cmMakefile* Makefile; +}; +#endif diff --git a/Source/cmState.cxx b/Source/cmState.cxx index 0b6b40f..73f166c 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -623,8 +623,7 @@ cmProp cmState::GetGlobalProperty(const std::string& prop) bool cmState::GetGlobalPropertyAsBool(const std::string& prop) { - cmProp p = this->GetGlobalProperty(prop); - return p && cmIsOn(*p); + return cmIsOn(this->GetGlobalProperty(prop)); } void cmState::SetSourceDirectory(std::string const& sourceDirectory) diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx index a4fe663..796bb1f 100644 --- a/Source/cmStateDirectory.cxx +++ b/Source/cmStateDirectory.cxx @@ -648,8 +648,7 @@ cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const bool cmStateDirectory::GetPropertyAsBool(const std::string& prop) const { - cmProp p = this->GetProperty(prop); - return p && cmIsOn(*p); + return cmIsOn(this->GetProperty(prop)); } std::vector<std::string> cmStateDirectory::GetPropertyKeys() const diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx index c223431..bf8e331 100644 --- a/Source/cmStateSnapshot.cxx +++ b/Source/cmStateSnapshot.cxx @@ -148,7 +148,7 @@ bool cmStateSnapshot::PopPolicy() bool cmStateSnapshot::CanPopPolicyScope() { - return this->Position->Policies == this->Position->PolicyScope; + return this->Position->Policies != this->Position->PolicyScope; } void cmStateSnapshot::SetPolicy(cmPolicies::PolicyID id, @@ -232,11 +232,6 @@ void cmStateSnapshot::RemoveDefinition(std::string const& name) this->Position->Vars->Unset(name); } -std::vector<std::string> cmStateSnapshot::UnusedKeys() const -{ - return this->Position->Vars->UnusedKeys(); -} - std::vector<std::string> cmStateSnapshot::ClosureKeys() const { return cmDefinitions::ClosureKeys(this->Position->Vars, @@ -328,7 +323,7 @@ void cmStateSnapshot::SetDefaultDefinitions() #if defined(__CYGWIN__) std::string legacy; if (cmSystemTools::GetEnv("CMAKE_LEGACY_CYGWIN_WIN32", legacy) && - cmIsOn(legacy.c_str())) { + cmIsOn(legacy)) { this->SetDefinition("WIN32", "1"); this->SetDefinition("CMAKE_HOST_WIN32", "1"); } diff --git a/Source/cmStateSnapshot.h b/Source/cmStateSnapshot.h index 021fd53..c19f174 100644 --- a/Source/cmStateSnapshot.h +++ b/Source/cmStateSnapshot.h @@ -28,7 +28,6 @@ public: bool IsInitialized(std::string const& name) const; void SetDefinition(std::string const& name, cm::string_view value); void RemoveDefinition(std::string const& name); - std::vector<std::string> UnusedKeys() const; std::vector<std::string> ClosureKeys() const; bool RaiseScope(std::string const& var, const char* varDef); diff --git a/Source/cmString.cxx b/Source/cmString.cxx index 2a0c125..898b828 100644 --- a/Source/cmString.cxx +++ b/Source/cmString.cxx @@ -17,7 +17,7 @@ static std::string const empty_string_; void String::internally_mutate_to_stable_string() { // We assume that only one thread mutates this instance at - // a time even if we point to a shared string buffer refernced + // a time even if we point to a shared string buffer referenced // by other threads. *this = String(data(), size()); } diff --git a/Source/cmString.hxx b/Source/cmString.hxx index 87bfdff..40fe20d 100644 --- a/Source/cmString.hxx +++ b/Source/cmString.hxx @@ -383,7 +383,7 @@ public: instance is mutated or destroyed. */ std::string const* str_if_stable() const; - /** Get a refernce to a normal std::string. The reference + /** Get a reference to a normal std::string. The reference is valid until this instance is mutated or destroyed. */ std::string const& str(); diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h index a5ecca7..4b0090b 100644 --- a/Source/cmStringAlgorithms.h +++ b/Source/cmStringAlgorithms.h @@ -20,6 +20,20 @@ /** String range type. */ using cmStringRange = cmRange<std::vector<std::string>::const_iterator>; +/** Check for non-empty string. */ +inline bool cmNonempty(const char* str) +{ + return str && *str; +} +inline bool cmNonempty(cm::string_view str) +{ + return !str.empty(); +} +inline bool cmNonempty(std::string const* str) +{ + return str && !str->empty(); +} + /** Callable string comparison struct. */ struct cmStrCmp { @@ -205,10 +219,11 @@ bool cmIsNOTFOUND(cm::string_view val); bool cmIsOn(cm::string_view val); inline bool cmIsOn(const char* val) { - if (!val) { - return false; - } - return cmIsOn(cm::string_view(val)); + return val && cmIsOn(cm::string_view(val)); +} +inline bool cmIsOn(std::string const* val) +{ + return val && cmIsOn(*val); } /** @@ -221,10 +236,11 @@ inline bool cmIsOn(const char* val) bool cmIsOff(cm::string_view val); inline bool cmIsOff(const char* val) { - if (!val) { - return true; - } - return cmIsOff(cm::string_view(val)); + return !val || cmIsOff(cm::string_view(val)); +} +inline bool cmIsOff(std::string const* val) +{ + return !val || cmIsOff(*val); } /** Returns true if string @a str starts with the character @a prefix. */ diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 1e78d36..798c29a 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1213,7 +1213,7 @@ bool cmSystemTools::UnsetEnv(const char* value) { # if !defined(HAVE_UNSETENV) std::string var = cmStrCat(value, '='); - return cmSystemTools::PutEnv(var.c_str()); + return cmSystemTools::PutEnv(var); # else unsetenv(value); return true; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 36e1ad5..60416a3 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -7,6 +7,7 @@ #include <cstring> #include <initializer_list> #include <iterator> +#include <map> #include <set> #include <sstream> #include <unordered_set> @@ -185,6 +186,7 @@ public: std::vector<cmInstallTargetGenerator*> InstallGenerators; std::set<std::string> SystemIncludeDirectories; cmTarget::LinkLibraryVectorType OriginalLinkLibraries; + std::map<std::string, BTs<std::string>> LanguageStandardProperties; std::vector<std::string> IncludeDirectoriesEntries; std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces; std::vector<std::string> CompileOptionsEntries; @@ -214,6 +216,15 @@ public: std::string ProcessSourceItemCMP0049(const std::string& s); }; +namespace { +#define SETUP_COMMON_LANGUAGE_PROPERTIES(lang) \ + initProp(#lang "_COMPILER_LAUNCHER"); \ + initProp(#lang "_STANDARD"); \ + initProp(#lang "_STANDARD_REQUIRED"); \ + initProp(#lang "_EXTENSIONS"); \ + initProp(#lang "_VISIBILITY_PRESET") +} + cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, Visibility vis, cmMakefile* mf, PerConfig perConfig) : impl(cm::make_unique<cmTargetInternals>()) @@ -270,8 +281,14 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, }; // Setup default property values. - if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && - this->GetType() != cmStateEnums::UTILITY) { + if (this->CanCompileSources()) { + + SETUP_COMMON_LANGUAGE_PROPERTIES(C); + SETUP_COMMON_LANGUAGE_PROPERTIES(OBJC); + SETUP_COMMON_LANGUAGE_PROPERTIES(CXX); + SETUP_COMMON_LANGUAGE_PROPERTIES(OBJCXX); + SETUP_COMMON_LANGUAGE_PROPERTIES(CUDA); + initProp("ANDROID_API"); initProp("ANDROID_API_MIN"); initProp("ANDROID_ARCH"); @@ -333,38 +350,22 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("NO_SYSTEM_FROM_IMPORTED"); initProp("BUILD_WITH_INSTALL_NAME_DIR"); initProp("C_CLANG_TIDY"); - initProp("C_COMPILER_LAUNCHER"); initProp("C_CPPLINT"); initProp("C_CPPCHECK"); initProp("C_INCLUDE_WHAT_YOU_USE"); initProp("LINK_WHAT_YOU_USE"); - initProp("C_STANDARD"); - initProp("C_STANDARD_REQUIRED"); - initProp("C_EXTENSIONS"); - initProp("OBJC_COMPILER_LAUNCHER"); - initProp("OBJC_STANDARD"); - initProp("OBJC_STANDARD_REQUIRED"); - initProp("OBJC_EXTENSIONS"); initProp("CXX_CLANG_TIDY"); - initProp("CXX_COMPILER_LAUNCHER"); initProp("CXX_CPPLINT"); initProp("CXX_CPPCHECK"); initProp("CXX_INCLUDE_WHAT_YOU_USE"); - initProp("CXX_STANDARD"); - initProp("CXX_STANDARD_REQUIRED"); - initProp("CXX_EXTENSIONS"); - initProp("OBJCXX_COMPILER_LAUNCHER"); - initProp("OBJCXX_STANDARD"); - initProp("OBJCXX_STANDARD_REQUIRED"); - initProp("OBJCXX_EXTENSIONS"); - initProp("CUDA_STANDARD"); - initProp("CUDA_STANDARD_REQUIRED"); - initProp("CUDA_EXTENSIONS"); - initProp("CUDA_COMPILER_LAUNCHER"); initProp("CUDA_SEPARABLE_COMPILATION"); initProp("CUDA_RESOLVE_DEVICE_SYMBOLS"); initProp("CUDA_RUNTIME_LIBRARY"); initProp("CUDA_ARCHITECTURES"); + initProp("VISIBILITY_INLINES_HIDDEN"); + initProp("JOB_POOL_COMPILE"); + initProp("JOB_POOL_LINK"); + initProp("JOB_POOL_PRECOMPILE_HEADER"); initProp("LINK_SEARCH_START_STATIC"); initProp("LINK_SEARCH_END_STATIC"); initProp("Swift_LANGUAGE_VERSION"); @@ -372,9 +373,11 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("VS_JUST_MY_CODE_DEBUGGING"); initProp("DISABLE_PRECOMPILE_HEADERS"); initProp("UNITY_BUILD"); + initProp("OPTIMIZE_DEPENDENCIES"); 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"); @@ -399,16 +402,15 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, #endif } - if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - initProp("FOLDER"); + initProp("FOLDER"); - if (this->GetGlobalGenerator()->IsXcode()) { - initProp("XCODE_GENERATE_SCHEME"); - } + if (this->GetGlobalGenerator()->IsXcode()) { + initProp("XCODE_GENERATE_SCHEME"); } // Setup per-configuration property default values. - if (this->GetType() != cmStateEnums::UTILITY) { + if (this->GetType() != cmStateEnums::UTILITY && + this->GetType() != cmStateEnums::GLOBAL_TARGET) { static const auto configProps = { /* clang-format needs this comment to break after the opening brace */ "ARCHIVE_OUTPUT_DIRECTORY_", "LIBRARY_OUTPUT_DIRECTORY_", @@ -417,8 +419,8 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, "INTERPROCEDURAL_OPTIMIZATION_" }; // Collect the set of configuration types. - std::vector<std::string> configNames; - mf->GetConfigurations(configNames); + std::vector<std::string> configNames = + mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig); for (std::string const& configName : configNames) { std::string configUpper = cmSystemTools::UpperCase(configName); for (auto const& prop : configProps) { @@ -485,16 +487,6 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, impl->Makefile->GetLinkDirectoriesBacktraces()); } - if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && - this->GetType() != cmStateEnums::UTILITY) { - initProp("C_VISIBILITY_PRESET"); - initProp("CXX_VISIBILITY_PRESET"); - initProp("OBJC_VISIBILITY_PRESET"); - initProp("OBJCXX_VISIBILITY_PRESET"); - initProp("CUDA_VISIBILITY_PRESET"); - initProp("VISIBILITY_INLINES_HIDDEN"); - } - if (impl->TargetType == cmStateEnums::EXECUTABLE) { initProp("ANDROID_GUI"); initProp("CROSSCOMPILING_EMULATOR"); @@ -503,6 +495,8 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, if (impl->TargetType == cmStateEnums::SHARED_LIBRARY || impl->TargetType == cmStateEnums::MODULE_LIBRARY) { this->SetProperty("POSITION_INDEPENDENT_CODE", "True"); + } else if (this->CanCompileSources()) { + initProp("POSITION_INDEPENDENT_CODE"); } if (impl->TargetType == cmStateEnums::SHARED_LIBRARY || impl->TargetType == cmStateEnums::EXECUTABLE) { @@ -510,11 +504,6 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("WINDOWS_EXPORT_ALL_SYMBOLS"); } - if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && - this->GetType() != cmStateEnums::UTILITY) { - initProp("POSITION_INDEPENDENT_CODE"); - } - // Record current policies for later use. impl->Makefile->RecordPolicies(impl->PolicyMap); @@ -526,36 +515,26 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW); } - if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && - this->GetType() != cmStateEnums::UTILITY) { - initProp("JOB_POOL_COMPILE"); - initProp("JOB_POOL_LINK"); - initProp("JOB_POOL_PRECOMPILE_HEADER"); - } - if (impl->TargetType <= cmStateEnums::GLOBAL_TARGET) { initProp("DOTNET_TARGET_FRAMEWORK"); initProp("DOTNET_TARGET_FRAMEWORK_VERSION"); } - if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - - // check for "CMAKE_VS_GLOBALS" variable and set up target properties - // if any - const char* globals = mf->GetDefinition("CMAKE_VS_GLOBALS"); - if (globals) { - const std::string genName = mf->GetGlobalGenerator()->GetName(); - if (cmHasLiteralPrefix(genName, "Visual Studio")) { - std::vector<std::string> props = cmExpandedList(globals); - const std::string vsGlobal = "VS_GLOBAL_"; - for (const std::string& i : props) { - // split NAME=VALUE - const std::string::size_type assignment = i.find('='); - if (assignment != std::string::npos) { - const std::string propName = vsGlobal + i.substr(0, assignment); - const std::string propValue = i.substr(assignment + 1); - initPropValue(propName, propValue.c_str()); - } + // check for "CMAKE_VS_GLOBALS" variable and set up target properties + // if any + const char* globals = mf->GetDefinition("CMAKE_VS_GLOBALS"); + if (globals) { + const std::string genName = mf->GetGlobalGenerator()->GetName(); + if (cmHasLiteralPrefix(genName, "Visual Studio")) { + std::vector<std::string> props = cmExpandedList(globals); + const std::string vsGlobal = "VS_GLOBAL_"; + for (const std::string& i : props) { + // split NAME=VALUE + const std::string::size_type assignment = i.find('='); + if (assignment != std::string::npos) { + const std::string propName = vsGlobal + i.substr(0, assignment); + const std::string propValue = i.substr(assignment + 1); + initPropValue(propName, propValue.c_str()); } } } @@ -598,6 +577,40 @@ cmGlobalGenerator* cmTarget::GetGlobalGenerator() const return impl->Makefile->GetGlobalGenerator(); } +BTs<std::string> const* cmTarget::GetLanguageStandardProperty( + const std::string& propertyName) const +{ + auto entry = impl->LanguageStandardProperties.find(propertyName); + if (entry != impl->LanguageStandardProperties.end()) { + return &entry->second; + } + + return nullptr; +} + +void cmTarget::SetLanguageStandardProperty(std::string const& lang, + std::string const& value, + const std::string& feature) +{ + cmListFileBacktrace featureBacktrace; + for (size_t i = 0; i < impl->CompileFeaturesEntries.size(); i++) { + if (impl->CompileFeaturesEntries[i] == feature) { + if (i < impl->CompileFeaturesBacktraces.size()) { + featureBacktrace = impl->CompileFeaturesBacktraces[i]; + } + break; + } + } + + BTs<std::string>& languageStandardProperty = + impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")]; + if (languageStandardProperty.Value != value) { + languageStandardProperty.Value = value; + languageStandardProperty.Backtraces.clear(); + } + languageStandardProperty.Backtraces.emplace_back(featureBacktrace); +} + void cmTarget::AddUtility(std::string const& name, bool cross, cmMakefile* mf) { impl->Utilities.insert(BT<std::pair<std::string, bool>>( @@ -636,6 +649,12 @@ bool cmTarget::IsAppBundleOnApple() const this->GetPropertyAsBool("MACOSX_BUNDLE")); } +bool cmTarget::IsAndroidGuiExecutable() const +{ + return (this->GetType() == cmStateEnums::EXECUTABLE && impl->IsAndroid && + this->GetPropertyAsBool("ANDROID_GUI")); +} + std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const { return impl->PreBuildCommands; @@ -1121,12 +1140,12 @@ cmBacktraceRange cmTarget::GetLinkImplementationBacktraces() const void cmTarget::SetProperty(const std::string& prop, const char* value) { - if (!cmTargetPropertyComputer::PassesWhitelist( - this->GetType(), prop, impl->Makefile->GetMessenger(), - impl->Makefile->GetBacktrace())) { - return; - } #define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP + MAKE_STATIC_PROP(C_STANDARD); + MAKE_STATIC_PROP(CXX_STANDARD); + MAKE_STATIC_PROP(CUDA_STANDARD); + MAKE_STATIC_PROP(OBJC_STANDARD); + MAKE_STATIC_PROP(OBJCXX_STANDARD); MAKE_STATIC_PROP(COMPILE_DEFINITIONS); MAKE_STATIC_PROP(COMPILE_FEATURES); MAKE_STATIC_PROP(COMPILE_OPTIONS); @@ -1310,6 +1329,15 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) cmProp tmp = reusedTarget->GetProperty("COMPILE_PDB_NAME"); this->SetProperty("COMPILE_PDB_NAME", tmp ? tmp->c_str() : nullptr); this->AddUtility(reusedFrom, false, impl->Makefile); + } else if (prop == propC_STANDARD || prop == propCXX_STANDARD || + prop == propCUDA_STANDARD || prop == propOBJC_STANDARD || + prop == propOBJCXX_STANDARD) { + if (value) { + impl->LanguageStandardProperties[prop] = + BTs<std::string>(value, impl->Makefile->GetBacktrace()); + } else { + impl->LanguageStandardProperties.erase(prop); + } } else { impl->Properties.SetProperty(prop, value); } @@ -1318,11 +1346,6 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) void cmTarget::AppendProperty(const std::string& prop, const std::string& value, bool asString) { - if (!cmTargetPropertyComputer::PassesWhitelist( - this->GetType(), prop, impl->Makefile->GetMessenger(), - impl->Makefile->GetBacktrace())) { - return; - } if (prop == "NAME") { impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, "NAME property is read-only\n"); @@ -1413,6 +1436,11 @@ void cmTarget::AppendProperty(const std::string& prop, } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) { impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, prop + " property may not be APPENDed."); + } else if (prop == "C_STANDARD" || prop == "CXX_STANDARD" || + prop == "CUDA_STANDARD" || prop == "OBJC_STANDARD" || + prop == "OBJCXX_STANDARD") { + impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, + prop + " property may not be appended."); } else { impl->Properties.AppendProperty(prop, value, asString); } @@ -1626,6 +1654,11 @@ cmProp cmTarget::GetComputedProperty(const std::string& prop, cmProp cmTarget::GetProperty(const std::string& prop) const { #define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP + MAKE_STATIC_PROP(C_STANDARD); + MAKE_STATIC_PROP(CXX_STANDARD); + MAKE_STATIC_PROP(CUDA_STANDARD); + MAKE_STATIC_PROP(OBJC_STANDARD); + MAKE_STATIC_PROP(OBJCXX_STANDARD); MAKE_STATIC_PROP(LINK_LIBRARIES); MAKE_STATIC_PROP(TYPE); MAKE_STATIC_PROP(INCLUDE_DIRECTORIES); @@ -1646,6 +1679,11 @@ cmProp cmTarget::GetProperty(const std::string& prop) const MAKE_STATIC_PROP(TRUE); #undef MAKE_STATIC_PROP static std::unordered_set<std::string> const specialProps{ + propC_STANDARD, + propCXX_STANDARD, + propCUDA_STANDARD, + propOBJC_STANDARD, + propOBJCXX_STANDARD, propLINK_LIBRARIES, propTYPE, propINCLUDE_DIRECTORIES, @@ -1664,6 +1702,15 @@ cmProp cmTarget::GetProperty(const std::string& prop) const propSOURCES }; if (specialProps.count(prop)) { + if (prop == propC_STANDARD || prop == propCXX_STANDARD || + prop == propCUDA_STANDARD || prop == propOBJC_STANDARD || + prop == propOBJCXX_STANDARD) { + auto propertyIter = impl->LanguageStandardProperties.find(prop); + if (propertyIter == impl->LanguageStandardProperties.end()) { + return nullptr; + } + return &(propertyIter->second.Value); + } if (prop == propLINK_LIBRARIES) { if (impl->LinkImplementationPropertyEntries.empty()) { return nullptr; @@ -1804,8 +1851,7 @@ std::string const& cmTarget::GetSafeProperty(std::string const& prop) const bool cmTarget::GetPropertyAsBool(const std::string& prop) const { - cmProp p = this->GetProperty(prop); - return p && cmIsOn(*p); + return cmIsOn(this->GetProperty(prop)); } cmPropertyMap const& cmTarget::GetProperties() const @@ -1838,6 +1884,27 @@ bool cmTarget::IsPerConfig() const return impl->PerConfig; } +bool cmTarget::CanCompileSources() const +{ + if (this->IsImported()) { + return false; + } + switch (this->GetType()) { + case cmStateEnums::EXECUTABLE: + case cmStateEnums::STATIC_LIBRARY: + case cmStateEnums::SHARED_LIBRARY: + case cmStateEnums::MODULE_LIBRARY: + case cmStateEnums::OBJECT_LIBRARY: + return true; + case cmStateEnums::UTILITY: + case cmStateEnums::INTERFACE_LIBRARY: + case cmStateEnums::GLOBAL_TARGET: + case cmStateEnums::UNKNOWN_LIBRARY: + break; + } + return false; +} + const char* cmTarget::GetSuffixVariableInternal( cmStateEnums::ArtifactType artifact) const { @@ -1865,7 +1932,7 @@ const char* cmTarget::GetSuffixVariableInternal( case cmStateEnums::RuntimeBinaryArtifact: // Android GUI application packages store the native // binary as a shared library. - return (impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI") + return (this->IsAndroidGuiExecutable() ? "CMAKE_SHARED_LIBRARY_SUFFIX" : "CMAKE_EXECUTABLE_SUFFIX"); case cmStateEnums::ImportLibraryArtifact: @@ -1906,7 +1973,7 @@ const char* cmTarget::GetPrefixVariableInternal( case cmStateEnums::RuntimeBinaryArtifact: // Android GUI application packages store the native // binary as a shared library. - return (impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI") + return (this->IsAndroidGuiExecutable() ? "CMAKE_SHARED_LIBRARY_PREFIX" : ""); case cmStateEnums::ImportLibraryArtifact: diff --git a/Source/cmTarget.h b/Source/cmTarget.h index f0ddb68..43f1887 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -196,6 +196,7 @@ public: bool IsImported() const; bool IsImportedGloballyVisible() const; bool IsPerConfig() const; + bool CanCompileSources() const; bool GetMappedConfig(std::string const& desired_config, cmProp& loc, cmProp& imp, std::string& suffix) const; @@ -209,6 +210,9 @@ public: //! Return whether this target is an executable Bundle on Apple. bool IsAppBundleOnApple() const; + //! Return whether this target is a GUI executable on Android. + bool IsAndroidGuiExecutable() const; + //! Get a backtrace from the creation of the target. cmListFileBacktrace const& GetBacktrace() const; @@ -233,6 +237,13 @@ public: void AddSystemIncludeDirectories(std::set<std::string> const& incs); std::set<std::string> const& GetSystemIncludeDirectories() const; + BTs<std::string> const* GetLanguageStandardProperty( + const std::string& propertyName) const; + + void SetLanguageStandardProperty(std::string const& lang, + std::string const& value, + const std::string& feature); + cmStringRange GetIncludeDirectoriesEntries() const; cmBacktraceRange GetIncludeDirectoriesBacktraces() const; diff --git a/Source/cmTargetCompileFeaturesCommand.cxx b/Source/cmTargetCompileFeaturesCommand.cxx index 06be4f0..aa1abdd 100644 --- a/Source/cmTargetCompileFeaturesCommand.cxx +++ b/Source/cmTargetCompileFeaturesCommand.cxx @@ -4,6 +4,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmStandardLevelResolver.h" #include "cmStringAlgorithms.h" #include "cmTargetPropCommandBase.h" @@ -29,9 +30,10 @@ private: const std::vector<std::string>& content, bool /*prepend*/, bool /*system*/) override { + cmStandardLevelResolver standardResolver(this->Makefile); for (std::string const& it : content) { std::string error; - if (!this->Makefile->AddRequiredTargetFeature(tgt, it, &error)) { + if (!standardResolver.AddRequiredTargetFeature(tgt, it, &error)) { this->SetError(error); return false; // Not (successfully) handled. } diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index e714720..9e30136 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -123,7 +123,7 @@ bool cmTargetPropCommandBase::ProcessContentArgs( } if (!content.empty()) { if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY && - scope != "INTERFACE") { + scope != "INTERFACE" && this->Property != "SOURCES") { this->SetError("may only set INTERFACE properties on INTERFACE targets"); return false; } diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx index f37995c..b9c9365 100644 --- a/Source/cmTargetPropertyComputer.cxx +++ b/Source/cmTargetPropertyComputer.cxx @@ -3,15 +3,12 @@ #include "cmTargetPropertyComputer.h" -#include <cctype> #include <sstream> -#include <unordered_set> #include "cmMessageType.h" #include "cmMessenger.h" #include "cmPolicies.h" #include "cmStateSnapshot.h" -#include "cmStringAlgorithms.h" bool cmTargetPropertyComputer::HandleLocationPropertyPolicy( std::string const& tgtName, cmMessenger* messenger, @@ -44,69 +41,3 @@ bool cmTargetPropertyComputer::HandleLocationPropertyPolicy( return messageType != MessageType::FATAL_ERROR; } - -bool cmTargetPropertyComputer::WhiteListedInterfaceProperty( - const std::string& prop) -{ - if (cmHasLiteralPrefix(prop, "INTERFACE_")) { - return true; - } - if (cmHasLiteralPrefix(prop, "_")) { - return true; - } - if (std::islower(prop[0])) { - return true; - } - static std::unordered_set<std::string> const builtIns{ - "COMPATIBLE_INTERFACE_BOOL", - "COMPATIBLE_INTERFACE_NUMBER_MAX", - "COMPATIBLE_INTERFACE_NUMBER_MIN", - "COMPATIBLE_INTERFACE_STRING", - "DEPRECATION", - "EXPORT_NAME", - "EXPORT_PROPERTIES", - "IMPORTED", - "IMPORTED_GLOBAL", - "MANUALLY_ADDED_DEPENDENCIES", - "NAME", - "PRIVATE_HEADER", - "PUBLIC_HEADER", - "TYPE" - }; - - if (builtIns.count(prop)) { - return true; - } - - if (prop == "IMPORTED_CONFIGURATIONS" || prop == "IMPORTED_LIBNAME" || - cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME_") || - cmHasLiteralPrefix(prop, "MAP_IMPORTED_CONFIG_")) { - return true; - } - - // This property should not be allowed but was incorrectly added in - // CMake 3.8. We can't remove it from the whitelist without breaking - // projects that try to set it. One day we could warn about this, but - // for now silently accept it. - if (prop == "NO_SYSTEM_FROM_IMPORTED") { - return true; - } - - return false; -} - -bool cmTargetPropertyComputer::PassesWhitelist( - cmStateEnums::TargetType tgtType, std::string const& prop, - cmMessenger* messenger, cmListFileBacktrace const& context) -{ - if (tgtType == cmStateEnums::INTERFACE_LIBRARY && - !WhiteListedInterfaceProperty(prop)) { - std::ostringstream e; - e << "INTERFACE_LIBRARY targets may only have whitelisted properties. " - "The property \"" - << prop << "\" is not allowed."; - messenger->IssueMessage(MessageType::FATAL_ERROR, e.str(), context); - return false; - } - return true; -} diff --git a/Source/cmTargetPropertyComputer.h b/Source/cmTargetPropertyComputer.h index f87b7c2..bafa43b 100644 --- a/Source/cmTargetPropertyComputer.h +++ b/Source/cmTargetPropertyComputer.h @@ -35,12 +35,6 @@ public: return nullptr; } - static bool WhiteListedInterfaceProperty(const std::string& prop); - - static bool PassesWhitelist(cmStateEnums::TargetType tgtType, - std::string const& prop, cmMessenger* messenger, - cmListFileBacktrace const& context); - private: static bool HandleLocationPropertyPolicy(std::string const& tgtName, cmMessenger* messenger, diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index af91177..da4593f 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -2,8 +2,12 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmTestGenerator.h" +#include <algorithm> +#include <cstddef> // IWYU pragma: keep +#include <iterator> #include <memory> #include <ostream> +#include <string> #include <utility> #include <vector> @@ -11,7 +15,10 @@ #include "cmGeneratorTarget.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmMessageType.h" #include "cmOutputConverter.h" +#include "cmPolicies.h" #include "cmProperty.h" #include "cmPropertyMap.h" #include "cmRange.h" @@ -20,6 +27,52 @@ #include "cmSystemTools.h" #include "cmTest.h" +namespace /* anonymous */ +{ + +bool needToQuoteTestName(const cmMakefile& mf, const std::string& name) +{ + // Determine if policy CMP0110 is set to NEW. + switch (mf.GetPolicyStatus(cmPolicies::CMP0110)) { + case cmPolicies::WARN: + // Only warn if a forbidden character is used in the name. + if (name.find_first_of("$[] #;\t\n\"\\") != std::string::npos) { + mf.IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0110), + "\nThe following name given to add_test() is invalid if " + "CMP0110 is not set or set to OLD:\n `", + name, "´\n")); + } + CM_FALLTHROUGH; + case cmPolicies::OLD: + // OLD behavior is to not quote the test's name. + return false; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + default: + // NEW behavior is to quote the test's name. + return true; + } +} + +std::size_t countMaxConsecutiveEqualSigns(const std::string& name) +{ + std::size_t max = 0; + auto startIt = find(name.begin(), name.end(), '='); + auto endIt = startIt; + for (; startIt != name.end(); startIt = find(endIt, name.end(), '=')) { + endIt = + find_if_not(startIt + 1, name.end(), [](char c) { return c == '='; }); + max = + std::max(max, static_cast<std::size_t>(std::distance(startIt, endIt))); + } + return max; +} + +} // End: anonymous namespace + cmTestGenerator::cmTestGenerator( cmTest* test, std::vector<std::string> const& configurations) : cmScriptGenerator("CTEST_CONFIGURATION_TYPE", configurations) @@ -76,8 +129,21 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, // Set up generator expression evaluation context. cmGeneratorExpression ge(this->Test->GetBacktrace()); + // Determine if policy CMP0110 is set to NEW. + const bool quote_test_name = + needToQuoteTestName(*this->Test->GetMakefile(), this->Test->GetName()); + // Determine the number of equal-signs needed for quoting test name with + // [==[...]==] syntax. + const std::string equalSigns( + 1 + countMaxConsecutiveEqualSigns(this->Test->GetName()), '='); + // Start the test command. - os << indent << "add_test(" << this->Test->GetName() << " "; + if (quote_test_name) { + os << indent << "add_test([" << equalSigns << "[" << this->Test->GetName() + << "]" << equalSigns << "] "; + } else { + os << indent << "add_test(" << this->Test->GetName() << " "; + } // Evaluate command line arguments std::vector<std::string> argv = @@ -102,7 +168,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, // Prepend with the emulator when cross compiling if required. cmProp emulator = target->GetProperty("CROSSCOMPILING_EMULATOR"); - if (emulator != nullptr && !emulator->empty()) { + if (cmNonempty(emulator)) { std::vector<std::string> emulatorWithArgs = cmExpandedList(*emulator); std::string emulatorExe(emulatorWithArgs[0]); cmSystemTools::ConvertToUnixSlashes(emulatorExe); @@ -127,8 +193,13 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, os << ")\n"; // Output properties for the test. - os << indent << "set_tests_properties(" << this->Test->GetName() - << " PROPERTIES "; + if (quote_test_name) { + os << indent << "set_tests_properties([" << equalSigns << "[" + << this->Test->GetName() << "]" << equalSigns << "] PROPERTIES "; + } else { + os << indent << "set_tests_properties(" << this->Test->GetName() + << " PROPERTIES "; + } for (auto const& i : this->Test->GetProperties().GetList()) { os << " " << i.first << " " << cmOutputConverter::EscapeForCMake( @@ -140,7 +211,21 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, void cmTestGenerator::GenerateScriptNoConfig(std::ostream& os, Indent indent) { - os << indent << "add_test(" << this->Test->GetName() << " NOT_AVAILABLE)\n"; + // Determine if policy CMP0110 is set to NEW. + const bool quote_test_name = + needToQuoteTestName(*this->Test->GetMakefile(), this->Test->GetName()); + // Determine the number of equal-signs needed for quoting test name with + // [==[...]==] syntax. + const std::string equalSigns( + 1 + countMaxConsecutiveEqualSigns(this->Test->GetName()), '='); + + if (quote_test_name) { + os << indent << "add_test([" << equalSigns << "[" << this->Test->GetName() + << "]" << equalSigns << "] NOT_AVAILABLE)\n"; + } else { + os << indent << "add_test(" << this->Test->GetName() + << " NOT_AVAILABLE)\n"; + } } bool cmTestGenerator::NeedsScriptNoConfig() const @@ -155,14 +240,27 @@ void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent) { this->TestGenerated = true; + // Determine if policy CMP0110 is set to NEW. + const bool quote_test_name = + needToQuoteTestName(*this->Test->GetMakefile(), this->Test->GetName()); + // Determine the number of equal-signs needed for quoting test name with + // [==[...]==] syntax. + const std::string equalSigns( + 1 + countMaxConsecutiveEqualSigns(this->Test->GetName()), '='); + // Get the test command line to be executed. std::vector<std::string> const& command = this->Test->GetCommand(); std::string exe = command[0]; cmSystemTools::ConvertToUnixSlashes(exe); - fout << indent; - fout << "add_test("; - fout << this->Test->GetName() << " \"" << exe << "\""; + if (quote_test_name) { + fout << indent << "add_test([" << equalSigns << "[" + << this->Test->GetName() << "]" << equalSigns << "] \"" << exe + << "\""; + } else { + 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 @@ -182,8 +280,13 @@ void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent) fout << ")\n"; // Output properties for the test. - fout << indent << "set_tests_properties(" << this->Test->GetName() - << " PROPERTIES "; + if (quote_test_name) { + fout << indent << "set_tests_properties([" << equalSigns << "[" + << this->Test->GetName() << "]" << equalSigns << "] PROPERTIES "; + } else { + fout << indent << "set_tests_properties(" << this->Test->GetName() + << " PROPERTIES "; + } for (auto const& i : this->Test->GetProperties().GetList()) { fout << " " << i.first << " " << cmOutputConverter::EscapeForCMake(i.second); diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index 13f73dc..bd6bb3d 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -164,7 +164,7 @@ std::string cmTimestamp::AddTimestampComponent(char flag, break; case 's': // Seconds since UNIX epoch (midnight 1-jan-1970) { - // Build a time_t for UNIX epoch and substract from the input "timeT": + // Build a time_t for UNIX epoch and subtract from the input "timeT": struct tm tmUnixEpoch; memset(&tmUnixEpoch, 0, sizeof(tmUnixEpoch)); tmUnixEpoch.tm_mday = 1; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index a8e424d..db9dc53 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -232,15 +232,17 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( , LocalGenerator( (cmLocalVisualStudio10Generator*)target->GetLocalGenerator()) { - this->Makefile->GetConfigurations(this->Configurations); + this->Configurations = + this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig); this->NsightTegra = gg->IsNsightTegra(); + this->Android = gg->TargetsAndroid(); for (int i = 0; i < 4; ++i) { this->NsightTegraVersion[i] = 0; } sscanf(gg->GetNsightTegraVersion().c_str(), "%u.%u.%u.%u", &this->NsightTegraVersion[0], &this->NsightTegraVersion[1], &this->NsightTegraVersion[2], &this->NsightTegraVersion[3]); - this->MSTools = !this->NsightTegra; + this->MSTools = !this->NsightTegra && !this->Android; this->Managed = false; this->TargetCompileAsWinRT = false; this->IsMissingFiles = false; @@ -313,8 +315,7 @@ std::ostream& cmVisualStudio10TargetGenerator::Elem::WriteString( void cmVisualStudio10TargetGenerator::Generate() { // do not generate external ms projects - if (this->GeneratorTarget->GetType() == cmStateEnums::INTERFACE_LIBRARY || - this->GeneratorTarget->GetProperty("EXTERNAL_MSPROJECT")) { + if (this->GeneratorTarget->GetProperty("EXTERNAL_MSPROJECT")) { return; } const std::string ProjectFileExtension = @@ -333,6 +334,13 @@ void cmVisualStudio10TargetGenerator::Generate() this->ProjectType = csproj; this->Managed = true; } + + if (this->Android && + this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE && + !this->GeneratorTarget->Target->IsAndroidGuiExecutable()) { + this->GlobalGenerator->AddAndroidExecutableWarning(this->Name); + } + // Tell the global generator the name of the project file this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME", this->Name); @@ -427,8 +435,8 @@ void cmVisualStudio10TargetGenerator::Generate() e1.Attribute("Label", "Globals"); e1.Element("ProjectGuid", "{" + this->GUID + "}"); - if (this->MSTools && - this->GeneratorTarget->GetType() <= cmStateEnums::GLOBAL_TARGET) { + if ((this->MSTools || this->Android) && + this->GeneratorTarget->IsInBuildSystem()) { this->WriteApplicationTypeSettings(e1); this->VerifyNecessaryFiles(); } @@ -469,7 +477,11 @@ void cmVisualStudio10TargetGenerator::Generate() cmProp vsGlobalKeyword = this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD"); if (!vsGlobalKeyword) { - e1.Element("Keyword", "Win32Proj"); + if (this->GlobalGenerator->TargetsAndroid()) { + e1.Element("Keyword", "Android"); + } else { + e1.Element("Keyword", "Win32Proj"); + } } else { e1.Element("Keyword", *vsGlobalKeyword); } @@ -592,11 +604,11 @@ void cmVisualStudio10TargetGenerator::Generate() } break; case cmStateEnums::UTILITY: + case cmStateEnums::INTERFACE_LIBRARY: case cmStateEnums::GLOBAL_TARGET: outputType = "Utility"; break; case cmStateEnums::UNKNOWN_LIBRARY: - case cmStateEnums::INTERFACE_LIBRARY: break; } e1.Element("OutputType", outputType); @@ -658,7 +670,7 @@ void cmVisualStudio10TargetGenerator::Generate() cmStrCat(this->DefaultArtifactDir, "\\nasm.props"); ConvertToWindowsSlash(propsLocal); this->Makefile->ConfigureFile(propsTemplate, propsLocal, false, true, - true); + true, true); Elem(e1, "Import").Attribute("Project", propsLocal); } } @@ -1134,14 +1146,17 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues(Elem& e0) break; case cmStateEnums::EXECUTABLE: if (this->NsightTegra && - !this->GeneratorTarget->GetPropertyAsBool("ANDROID_GUI")) { + !this->GeneratorTarget->Target->IsAndroidGuiExecutable()) { // Android executables are .so too. configType = "DynamicLibrary"; + } else if (this->Android) { + configType = "DynamicLibrary"; } else { configType = "Application"; } break; case cmStateEnums::UTILITY: + case cmStateEnums::INTERFACE_LIBRARY: case cmStateEnums::GLOBAL_TARGET: if (this->NsightTegra) { // Tegra-Android platform does not understand "Utility". @@ -1151,7 +1166,6 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues(Elem& e0) } break; case cmStateEnums::UNKNOWN_LIBRARY: - case cmStateEnums::INTERFACE_LIBRARY: break; } } @@ -1166,6 +1180,8 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues(Elem& e0) } } else if (this->NsightTegra) { this->WriteNsightTegraConfigurationValues(e1, c); + } else if (this->Android) { + this->WriteAndroidConfigurationValues(e1, c); } } } @@ -1324,6 +1340,24 @@ void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues( } } +void cmVisualStudio10TargetGenerator::WriteAndroidConfigurationValues( + Elem& e1, std::string const&) +{ + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; + 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 (cmProp stlType = + this->GeneratorTarget->GetProperty("ANDROID_STL_TYPE")) { + if (*stlType != "none") { + e1.Element("UseOfStl", *stlType); + } + } +} + void cmVisualStudio10TargetGenerator::WriteCustomCommands(Elem& e0) { this->CSharpCustomCommandNames.clear(); @@ -1941,7 +1975,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, } cmProp toolOverride = sf->GetProperty("VS_TOOL_OVERRIDE"); - if (toolOverride && !toolOverride->empty()) { + if (cmNonempty(toolOverride)) { tool = toolOverride->c_str(); } @@ -1950,12 +1984,12 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, if (this->GlobalGenerator->TargetsWindowsPhone() || this->GlobalGenerator->TargetsWindowsStore()) { cmProp content = sf->GetProperty("VS_DEPLOYMENT_CONTENT"); - if (content && !content->empty()) { + if (cmNonempty(content)) { toolHasSettings = true; deployContent = *content; cmProp location = sf->GetProperty("VS_DEPLOYMENT_LOCATION"); - if (location && !location->empty()) { + if (cmNonempty(location)) { deployLocation = *location; } } @@ -2117,7 +2151,7 @@ void cmVisualStudio10TargetGenerator::WriteSource(Elem& e2, void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) { - if (this->GeneratorTarget->GetType() > cmStateEnums::UTILITY) { + if (this->GeneratorTarget->GetType() == cmStateEnums::GLOBAL_TARGET) { return; } @@ -2258,7 +2292,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) e2.Attribute("UnityFilesDirectory", unityDir); } else { // Visual Studio versions prior to 2017 15.8 do not know about unity - // builds, thus we exclude the files alredy part of unity sources. + // builds, thus we exclude the files already part of unity sources. if (!si.Source->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION")) { exclude_configs = si.Configs; } @@ -2915,7 +2949,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( } } - if (this->MSTools) { + if (this->Android) { + e2.Element("ObjectFileName", "$(IntDir)%(filename).o"); + } else if (this->MSTools) { cmsys::RegularExpression clangToolset("v[0-9]+_clang_.*"); const char* toolset = this->GlobalGenerator->GetPlatformToolset(); if (toolset && clangToolset.find(toolset)) { @@ -4021,8 +4057,7 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups(Elem& e0) // output manifest flags <Manifest></Manifest> this->WriteManifestOptions(e1, c); if (this->NsightTegra && - this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE && - this->GeneratorTarget->GetPropertyAsBool("ANDROID_GUI")) { + this->GeneratorTarget->Target->IsAndroidGuiExecutable()) { this->WriteAntBuildOptions(e1, c); } } @@ -4108,7 +4143,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0) Elem e1(e0, "ItemGroup"); e1.SetHasElements(); for (cmGeneratorTarget const* dt : depends) { - if (dt->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + if (!dt->IsInBuildSystem()) { continue; } // skip fortran targets as they can not be processed by MSBuild @@ -4137,8 +4172,9 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0) } // Don't reference targets that don't produce any output. - if (dt->GetManagedType(this->Configurations[0]) == - cmGeneratorTarget::ManagedType::Undefined) { + if (this->Configurations.empty() || + dt->GetManagedType(this->Configurations[0]) == + cmGeneratorTarget::ManagedType::Undefined) { e2.Element("ReferenceOutputAssembly", "false"); e2.Element("CopyToOutputDirectory", "Never"); } @@ -4354,6 +4390,7 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1) bool isAppContainer = false; bool const isWindowsPhone = this->GlobalGenerator->TargetsWindowsPhone(); bool const isWindowsStore = this->GlobalGenerator->TargetsWindowsStore(); + bool const isAndroid = this->GlobalGenerator->TargetsAndroid(); std::string const& rev = this->GlobalGenerator->GetApplicationTypeRevision(); if (isWindowsPhone || isWindowsStore) { e1.Element("ApplicationType", @@ -4391,13 +4428,19 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1) this->Name + "_$(Configuration)_$(Platform).xap"); } } + } else if (isAndroid) { + e1.Element("ApplicationType", "Android"); + e1.Element("ApplicationTypeRevision", + gg->GetAndroidApplicationTypeRevision()); } if (isAppContainer) { e1.Element("AppContainerApplication", "true"); - } else if (this->Platform == "ARM64") { - e1.Element("WindowsSDKDesktopARM64Support", "true"); - } else if (this->Platform == "ARM") { - e1.Element("WindowsSDKDesktopARMSupport", "true"); + } else if (!isAndroid) { + if (this->Platform == "ARM64") { + e1.Element("WindowsSDKDesktopARM64Support", "true"); + } else if (this->Platform == "ARM") { + e1.Element("WindowsSDKDesktopARMSupport", "true"); + } } std::string const& targetPlatformVersion = gg->GetWindowsTargetPlatformVersion(); diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 7c71de3..c54057a 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -70,6 +70,7 @@ private: void WriteExtraSource(Elem& e1, cmSourceFile const* sf); void WriteNsightTegraConfigurationValues(Elem& e1, std::string const& config); + void WriteAndroidConfigurationValues(Elem& e1, std::string const& config); void WriteSource(Elem& e2, cmSourceFile const* sf); void WriteExcludeFromBuild(Elem& e2, std::vector<size_t> const& exclude_configs); @@ -215,6 +216,7 @@ private: bool MSTools; bool Managed; bool NsightTegra; + bool Android; unsigned int NsightTegraVersion[4]; bool TargetCompileAsWinRT; std::set<std::string> IPOEnabledConfigurations; diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx index f4c2f2d..55e941d 100644 --- a/Source/cmXCodeScheme.cxx +++ b/Source/cmXCodeScheme.cxx @@ -33,7 +33,7 @@ void cmXCodeScheme::WriteXCodeSharedScheme(const std::string& xcProjDir, // Create shared scheme sub-directory tree // std::string xcodeSchemeDir = cmStrCat(xcProjDir, "/xcshareddata/xcschemes"); - cmSystemTools::MakeDirectory(xcodeSchemeDir.c_str()); + cmSystemTools::MakeDirectory(xcodeSchemeDir); std::string xcodeSchemeFile = cmStrCat(xcodeSchemeDir, '/', this->TargetName, ".xcscheme"); @@ -324,8 +324,7 @@ bool cmXCodeScheme::WriteLaunchActionBooleanAttribute( bool defaultValue) { cmProp property = Target->GetTarget()->GetProperty(varName); - bool isOn = - (property == nullptr && defaultValue) || (property && cmIsOn(*property)); + bool isOn = (property == nullptr && defaultValue) || cmIsOn(property); if (isOn) { xout.Attribute(attrName.c_str(), "YES"); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 162e807..f630a7e 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -64,10 +64,6 @@ # include "cmVariableWatch.h" #endif -#if !defined(CMAKE_BOOTSTRAP) -# define CMAKE_USE_ECLIPSE -#endif - #if defined(__MINGW32__) && defined(CMAKE_BOOTSTRAP) # define CMAKE_BOOT_MINGW #endif @@ -97,20 +93,21 @@ #if defined(CMAKE_USE_WMAKE) # include "cmGlobalWatcomWMakeGenerator.h" #endif -#include "cmGlobalUnixMakefileGenerator3.h" #if !defined(CMAKE_BOOTSTRAP) # include "cmGlobalNinjaGenerator.h" +# include "cmGlobalUnixMakefileGenerator3.h" +#elif defined(CMAKE_BOOTSTRAP_MAKEFILES) +# include "cmGlobalUnixMakefileGenerator3.h" +#elif defined(CMAKE_BOOTSTRAP_NINJA) +# include "cmGlobalNinjaGenerator.h" #endif -#include "cmExtraCodeLiteGenerator.h" -#if !defined(CMAKE_BOOT_MINGW) +#if !defined(CMAKE_BOOTSTRAP) # include "cmExtraCodeBlocksGenerator.h" -#endif -#include "cmExtraKateGenerator.h" -#include "cmExtraSublimeTextGenerator.h" - -#ifdef CMAKE_USE_ECLIPSE +# include "cmExtraCodeLiteGenerator.h" # include "cmExtraEclipseCDT4Generator.h" +# include "cmExtraKateGenerator.h" +# include "cmExtraSublimeTextGenerator.h" #endif #if defined(__linux__) || defined(_WIN32) @@ -201,7 +198,7 @@ cmake::cmake(Role role, cmState::Mode mode) }; // The "c" extension MUST precede the "C" extension. - setupExts(this->SourceFileExtensions, + setupExts(this->CLikeSourceFileExtensions, { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "m", "M", "mm" }); setupExts(this->HeaderFileExtensions, { "h", "hh", "h++", "hm", "hpp", "hxx", "in", "txx" }); @@ -780,8 +777,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) std::cout << "Warn about uninitialized values.\n"; this->SetWarnUninitialized(true); } else if (cmHasLiteralPrefix(arg, "--warn-unused-vars")) { - std::cout << "Finding unused variables.\n"; - this->SetWarnUnused(true); + // Option was removed. } else if (cmHasLiteralPrefix(arg, "--no-warn-unused-cli")) { std::cout << "Not searching for unused variables given on the " << "command line.\n"; @@ -1137,13 +1133,9 @@ void cmake::AddDefaultExtraGenerators() #if !defined(CMAKE_BOOTSTRAP) this->ExtraGenerators.push_back(cmExtraCodeBlocksGenerator::GetFactory()); this->ExtraGenerators.push_back(cmExtraCodeLiteGenerator::GetFactory()); - this->ExtraGenerators.push_back(cmExtraSublimeTextGenerator::GetFactory()); - this->ExtraGenerators.push_back(cmExtraKateGenerator::GetFactory()); - -# ifdef CMAKE_USE_ECLIPSE this->ExtraGenerators.push_back(cmExtraEclipseCDT4Generator::GetFactory()); -# endif - + this->ExtraGenerators.push_back(cmExtraKateGenerator::GetFactory()); + this->ExtraGenerators.push_back(cmExtraSublimeTextGenerator::GetFactory()); #endif } @@ -1383,7 +1375,7 @@ struct SaveCacheEntry int cmake::HandleDeleteCacheVariables(const std::string& var) { - std::vector<std::string> argsSplit = cmExpandedList(std::string(var), true); + std::vector<std::string> argsSplit = cmExpandedList(var, true); // erase the property to avoid infinite recursion this->State->SetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_", ""); if (this->State->GetIsInTryCompile()) { @@ -1402,8 +1394,13 @@ int cmake::HandleDeleteCacheVariables(const std::string& var) save.key = *i; warning << *i << "= "; i++; - save.value = *i; - warning << *i << "\n"; + if (i != argsSplit.end()) { + save.value = *i; + warning << *i << "\n"; + } else { + warning << "\n"; + i -= 1; + } cmProp existingValue = this->State->GetCacheEntryValue(save.key); if (existingValue) { save.type = this->State->GetCacheEntryType(save.key); @@ -1499,10 +1496,10 @@ int cmake::Configure() this->Messenger->SetSuppressDeprecatedWarnings(value && cmIsOff(*value)); value = this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED"); - this->Messenger->SetDeprecatedWarningsAsErrors(value && cmIsOn(*value)); + this->Messenger->SetDeprecatedWarningsAsErrors(cmIsOn(value)); value = this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_WARNINGS"); - this->Messenger->SetSuppressDevWarnings(value && cmIsOn(*value)); + this->Messenger->SetSuppressDevWarnings(cmIsOn(value)); value = this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_ERRORS"); this->Messenger->SetDevWarningsAsErrors(value && cmIsOff(*value)); @@ -1757,6 +1754,9 @@ std::unique_ptr<cmGlobalGenerator> cmake::EvaluateDefaultGlobalGenerator() gen = cm::make_unique<cmGlobalNMakeMakefileGenerator>(this); } return std::unique_ptr<cmGlobalGenerator>(std::move(gen)); +#elif defined(CMAKE_BOOTSTRAP_NINJA) + return std::unique_ptr<cmGlobalGenerator>( + cm::make_unique<cmGlobalNinjaGenerator>(this)); #else return std::unique_ptr<cmGlobalGenerator>( cm::make_unique<cmGlobalUnixMakefileGenerator3>(this)); @@ -1970,6 +1970,17 @@ void cmake::AddGlobCacheEntry(bool recurse, bool listDirectories, backtrace); } +std::vector<std::string> cmake::GetAllExtensions() const +{ + std::vector<std::string> allExt = this->CLikeSourceFileExtensions.ordered; + allExt.insert(allExt.end(), this->HeaderFileExtensions.ordered.begin(), + this->HeaderFileExtensions.ordered.end()); + // cuda extensions are also in SourceFileExtensions so we ignore it here + allExt.insert(allExt.end(), this->FortranFileExtensions.ordered.begin(), + this->FortranFileExtensions.ordered.end()); + return allExt; +} + std::string cmake::StripExtension(const std::string& file) const { auto dotpos = file.rfind('.'); @@ -1979,7 +1990,7 @@ std::string cmake::StripExtension(const std::string& file) const #else auto ext = cm::string_view(file).substr(dotpos + 1); #endif - if (this->IsSourceExtension(ext) || this->IsHeaderExtension(ext)) { + if (this->IsAKnownExtension(ext)) { return file.substr(0, dotpos); } } @@ -2022,13 +2033,17 @@ void cmake::AddDefaultGenerators() this->Generators.push_back(cmGlobalMSYSMakefileGenerator::NewFactory()); this->Generators.push_back(cmGlobalMinGWMakefileGenerator::NewFactory()); #endif - this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory()); #if !defined(CMAKE_BOOTSTRAP) # if defined(__linux__) || defined(_WIN32) this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory()); # endif + this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory()); this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory()); this->Generators.push_back(cmGlobalNinjaMultiGenerator::NewFactory()); +#elif defined(CMAKE_BOOTSTRAP_NINJA) + this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory()); +#elif defined(CMAKE_BOOTSTRAP_MAKEFILES) + this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory()); #endif #if defined(CMAKE_USE_WMAKE) this->Generators.push_back(cmGlobalWatcomWMakeGenerator::NewFactory()); @@ -2269,7 +2284,7 @@ int cmake::CheckBuildSystem() if (this->ClearBuildSystem) { // Get the generator used for this build system. const char* genName = mf.GetDefinition("CMAKE_DEPENDS_GENERATOR"); - if (!genName || genName[0] == '\0') { + if (!cmNonempty(genName)) { genName = "Unix Makefiles"; } @@ -2743,9 +2758,7 @@ int cmake::Build(int jobs, const std::string& dir, } projName = *cachedProjectName; - cmProp cachedVerbose = - this->State->GetCacheEntryValue("CMAKE_VERBOSE_MAKEFILE"); - if (cachedVerbose && cmIsOn(*cachedVerbose)) { + if (cmIsOn(this->State->GetCacheEntryValue("CMAKE_VERBOSE_MAKEFILE"))) { verbose = true; } diff --git a/Source/cmake.h b/Source/cmake.h index 086ec87..0c4f429 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -264,44 +264,33 @@ public: this->GeneratorToolsetSet = true; } - const std::vector<std::string>& GetSourceExtensions() const + bool IsAKnownSourceExtension(cm::string_view ext) const { - return this->SourceFileExtensions.ordered; + return this->CLikeSourceFileExtensions.Test(ext) || + this->CudaFileExtensions.Test(ext) || + this->FortranFileExtensions.Test(ext); } - bool IsSourceExtension(cm::string_view ext) const + bool IsACLikeSourceExtension(cm::string_view ext) const { - return this->SourceFileExtensions.Test(ext); + return this->CLikeSourceFileExtensions.Test(ext); } - const std::vector<std::string>& GetHeaderExtensions() const - { - return this->HeaderFileExtensions.ordered; - } - - bool IsHeaderExtension(cm::string_view ext) const - { - return this->HeaderFileExtensions.Test(ext); - } - - const std::vector<std::string>& GetCudaExtensions() const + bool IsAKnownExtension(cm::string_view ext) const { - return this->CudaFileExtensions.ordered; + return this->IsAKnownSourceExtension(ext) || this->IsAHeaderExtension(ext); } - bool IsCudaExtension(cm::string_view ext) const - { - return this->CudaFileExtensions.Test(ext); - } + std::vector<std::string> GetAllExtensions() const; - const std::vector<std::string>& GetFortranExtensions() const + const std::vector<std::string>& GetHeaderExtensions() const { - return this->FortranFileExtensions.ordered; + return this->HeaderFileExtensions.ordered; } - bool IsFortranExtension(cm::string_view ext) const + bool IsAHeaderExtension(cm::string_view ext) const { - return this->FortranFileExtensions.Test(ext); + return this->HeaderFileExtensions.Test(ext); } // Strips the extension (if present and known) from a filename @@ -461,8 +450,6 @@ public: bool GetWarnUninitialized() { return this->WarnUninitialized; } void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; } - bool GetWarnUnused() { return this->WarnUnused; } - void SetWarnUnused(bool b) { this->WarnUnused = b; } bool GetWarnUnusedCli() { return this->WarnUnusedCli; } void SetWarnUnusedCli(bool b) { this->WarnUnusedCli = b; } bool GetCheckSystemVars() { return this->CheckSystemVars; } @@ -616,7 +603,6 @@ private: TraceFormat TraceFormatVar = TRACE_HUMAN; cmGeneratedFileStream TraceFile; bool WarnUninitialized = false; - bool WarnUnused = false; bool WarnUnusedCli = true; bool CheckSystemVars = false; std::map<std::string, bool> UsedCliVariables; @@ -628,7 +614,7 @@ private: std::string CheckStampList; std::string VSSolutionFile; std::string EnvironmentGenerator; - FileExtensions SourceFileExtensions; + FileExtensions CLikeSourceFileExtensions; FileExtensions HeaderFileExtensions; FileExtensions CudaFileExtensions; FileExtensions FortranFileExtensions; diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index d662a9a..4600fc5 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -3,11 +3,13 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <algorithm> #include <cassert> #include <cctype> #include <climits> #include <cstring> #include <iostream> +#include <sstream> #include <string> #include <vector> @@ -69,7 +71,7 @@ const char* cmDocumentationOptions[][2] = { { "--open <dir>", "Open generated project in the associated application." }, { "-N", "View mode only." }, { "-P <file>", "Process script mode." }, - { "--find-package", "Run in pkg-config like mode." }, + { "--find-package", "Legacy pkg-config like mode. Do not use." }, { "--graphviz=[file]", "Generate graphviz of dependencies, see " "CMakeGraphVizOptions.cmake for more." }, @@ -91,7 +93,6 @@ const char* cmDocumentationOptions[][2] = { { "--trace-redirect=<file>", "Redirect trace output to a file instead of stderr." }, { "--warn-uninitialized", "Warn about uninitialized values." }, - { "--warn-unused-vars", "Warn about unused variables." }, { "--no-warn-unused-cli", "Don't warn about command line options." }, { "--check-system-vars", "Find problems with variable usage in system " @@ -519,6 +520,121 @@ int do_build(int ac, char const* const* av) #endif } +bool parse_default_directory_permissions(const std::string& permissions, + std::string& parsedPermissionsVar) +{ + std::vector<std::string> parsedPermissions; + enum Doing + { + DoingNone, + DoingOwner, + DoingGroup, + DoingWorld, + DoingOwnerAssignment, + DoingGroupAssignment, + DoingWorldAssignment, + }; + Doing doing = DoingNone; + + auto uniquePushBack = [&parsedPermissions](const std::string& e) { + if (std::find(parsedPermissions.begin(), parsedPermissions.end(), e) == + parsedPermissions.end()) { + parsedPermissions.push_back(e); + } + }; + + for (auto const& e : permissions) { + switch (doing) { + case DoingNone: + if (e == 'u') { + doing = DoingOwner; + } else if (e == 'g') { + doing = DoingGroup; + } else if (e == 'o') { + doing = DoingWorld; + } else { + return false; + } + break; + case DoingOwner: + if (e == '=') { + doing = DoingOwnerAssignment; + } else { + return false; + } + break; + case DoingGroup: + if (e == '=') { + doing = DoingGroupAssignment; + } else { + return false; + } + break; + case DoingWorld: + if (e == '=') { + doing = DoingWorldAssignment; + } else { + return false; + } + break; + case DoingOwnerAssignment: + if (e == 'r') { + uniquePushBack("OWNER_READ"); + } else if (e == 'w') { + uniquePushBack("OWNER_WRITE"); + } else if (e == 'x') { + uniquePushBack("OWNER_EXECUTE"); + } else if (e == ',') { + doing = DoingNone; + } else { + return false; + } + break; + case DoingGroupAssignment: + if (e == 'r') { + uniquePushBack("GROUP_READ"); + } else if (e == 'w') { + uniquePushBack("GROUP_WRITE"); + } else if (e == 'x') { + uniquePushBack("GROUP_EXECUTE"); + } else if (e == ',') { + doing = DoingNone; + } else { + return false; + } + break; + case DoingWorldAssignment: + if (e == 'r') { + uniquePushBack("WORLD_READ"); + } else if (e == 'w') { + uniquePushBack("WORLD_WRITE"); + } else if (e == 'x') { + uniquePushBack("WORLD_EXECUTE"); + } else if (e == ',') { + doing = DoingNone; + } else { + return false; + } + break; + } + } + if (doing != DoingOwnerAssignment && doing != DoingGroupAssignment && + doing != DoingWorldAssignment) { + return false; + } + + std::ostringstream oss; + for (auto i = 0u; i < parsedPermissions.size(); i++) { + if (i != 0) { + oss << ";"; + } + oss << parsedPermissions[i]; + } + + parsedPermissionsVar = oss.str(); + return true; +} + int do_install(int ac, char const* const* av) { #ifdef CMAKE_BOOTSTRAP @@ -529,6 +645,7 @@ int do_install(int ac, char const* const* av) std::string config; std::string component; + std::string defaultDirectoryPermissions; std::string prefix; std::string dir; bool strip = false; @@ -541,6 +658,7 @@ int do_install(int ac, char const* const* av) DoingConfig, DoingComponent, DoingPrefix, + DoingDefaultDirectoryPermissions, }; Doing doing = DoingDir; @@ -559,6 +677,8 @@ int do_install(int ac, char const* const* av) (strcmp(av[i], "-v") == 0)) { verbose = true; doing = DoingNone; + } else if (strcmp(av[i], "--default-directory-permissions") == 0) { + doing = DoingDefaultDirectoryPermissions; } else { switch (doing) { case DoingDir: @@ -577,6 +697,10 @@ int do_install(int ac, char const* const* av) prefix = av[i]; doing = DoingNone; break; + case DoingDefaultDirectoryPermissions: + defaultDirectoryPermissions = av[i]; + doing = DoingNone; + break; default: std::cerr << "Unknown argument " << av[i] << std::endl; dir.clear(); @@ -593,6 +717,8 @@ int do_install(int ac, char const* const* av) " <dir> = Project binary directory to install.\n" " --config <cfg> = For multi-configuration tools, choose <cfg>.\n" " --component <comp> = Component-based install. Only install <comp>.\n" + " --default-directory-permissions <permission> \n" + " Default install permission. Use default permission <permission>.\n" " --prefix <prefix> = The installation prefix CMAKE_INSTALL_PREFIX.\n" " --strip = Performing install/strip.\n" " -v --verbose = Enable verbose output.\n" @@ -633,6 +759,18 @@ int do_install(int ac, char const* const* av) args.emplace_back("-DCMAKE_INSTALL_CONFIG_NAME=" + config); } + if (!defaultDirectoryPermissions.empty()) { + std::string parsedPermissionsVar; + if (!parse_default_directory_permissions(defaultDirectoryPermissions, + parsedPermissionsVar)) { + std::cerr << "--default-directory-permissions is in incorrect format" + << std::endl; + return 1; + } + args.emplace_back("-DCMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS=" + + parsedPermissionsVar); + } + args.emplace_back("-P"); args.emplace_back(dir + "/cmake_install.cmake"); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index de76d73..15d2fd1 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -126,6 +126,7 @@ void CMakeCommandUsage(const char* program) << " touch <file>... - touch a <file>.\n" << " touch_nocreate <file>... - touch a <file> but do not create it.\n" << " create_symlink old new - create a symbolic link new -> old\n" + << " create_hardlink old new - create a hard link new -> old\n" << " true - do nothing with an exit code of 0\n" << " false - do nothing with an exit code of 1\n" #if defined(_WIN32) && !defined(__CYGWIN__) @@ -582,12 +583,10 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) filesDiffer = cmsys::SystemTools::TextFilesDiffer(args[3], args[4]); } else { ::CMakeCommandUsage(args[0].c_str()); - return 1; + return 2; } if (filesDiffer) { - std::cerr << "Files \"" << args[args.size() - 2] << "\" to \"" - << args[args.size() - 1] << "\" are different.\n"; return 1; } return 0; @@ -602,8 +601,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) } cmsys::ifstream fin(args[3].c_str(), std::ios::in | std::ios::binary); if (!fin) { - std::cerr << "could not open object list file: " << args[3].c_str() - << "\n"; + std::cerr << "could not open object list file: " << args[3] << "\n"; return 1; } std::vector<std::string> files; @@ -626,13 +624,12 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) } FILE* fout = cmsys::SystemTools::Fopen(args[2], "w+"); if (!fout) { - std::cerr << "could not open output .def file: " << args[2].c_str() - << "\n"; + std::cerr << "could not open output .def file: " << args[2] << "\n"; return 1; } bindexplib deffile; if (args.size() >= 5) { - auto a = args[4]; + std::string const& a = args[4]; if (cmHasLiteralPrefix(a, "--nm=")) { deffile.SetNmPath(a.substr(5)); std::cerr << a.substr(5) << "\n"; @@ -640,7 +637,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) std::cerr << "unknown argument: " << a << "\n"; } } - for (auto const& file : files) { + for (std::string const& file : files) { std::string const& ext = cmSystemTools::GetFilenameLastExtension(file); if (cmSystemTools::LowerCase(ext) == ".def") { if (!deffile.AddDefinitionFile(file.c_str())) { @@ -1022,7 +1019,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) // Command to create a symbolic link. Fails on platforms not // supporting them. if (args[1] == "create_symlink" && args.size() == 4) { - const char* destinationFileName = args[3].c_str(); + std::string const& destinationFileName = args[3]; if ((cmSystemTools::FileExists(destinationFileName) || cmSystemTools::FileIsSymlink(destinationFileName)) && !cmSystemTools::RemoveFile(destinationFileName)) { @@ -1038,6 +1035,34 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) return 0; } + // Command to create a hard link. Fails on platforms not + // supporting them. + if (args[1] == "create_hardlink" && args.size() == 4) { + const char* SouceFileName = args[2].c_str(); + const char* destinationFileName = args[3].c_str(); + + if (!cmSystemTools::FileExists(SouceFileName)) { + std::cerr << "failed to create hard link because source path '" + << SouceFileName << "' does not exist \n"; + return 1; + } + + if ((cmSystemTools::FileExists(destinationFileName) || + cmSystemTools::FileIsSymlink(destinationFileName)) && + !cmSystemTools::RemoveFile(destinationFileName)) { + std::string emsg = cmSystemTools::GetLastSystemError(); + std::cerr << "failed to create hard link '" << destinationFileName + << "' because existing path cannot be removed: " << emsg + << "\n"; + return 1; + } + + if (!cmSystemTools::CreateLink(args[2], args[3])) { + return 1; + } + return 0; + } + // Command to do nothing with an exit code of 0. if (args[1] == "true") { return 0; @@ -1136,7 +1161,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) return cmcmd::ExecuteLinkScript(args); } -#ifndef CMAKE_BOOTSTRAP +#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_NINJA) // Internal CMake ninja dependency scanning support. if (args[1] == "cmake_ninja_depends") { return cmcmd_cmake_ninja_depends(args.begin() + 2, args.end()); @@ -1379,15 +1404,12 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) #if defined(_WIN32) && !defined(__CYGWIN__) // Write registry value if (args[1] == "write_regv" && args.size() > 3) { - return cmSystemTools::WriteRegistryValue(args[2].c_str(), - args[3].c_str()) - ? 0 - : 1; + return cmSystemTools::WriteRegistryValue(args[2], args[3]) ? 0 : 1; } // Delete registry value if (args[1] == "delete_regv" && args.size() > 2) { - return cmSystemTools::DeleteRegistryValue(args[2].c_str()) ? 0 : 1; + return cmSystemTools::DeleteRegistryValue(args[2]) ? 0 : 1; } // Remove file @@ -1750,7 +1772,7 @@ int cmcmd::RunLLVMRC(std::vector<std::string> const& args) // args[2] == source_file_path // args[3] == intermediate_file // args[4..n] == preprocess+args - // args[n+1] == -- + // args[n+1] == ++ // args[n+2...] == llvm-rc+args if (args.size() < 3) { std::cerr << "Invalid cmake_llvm_rc arguments"; @@ -1762,7 +1784,11 @@ int cmcmd::RunLLVMRC(std::vector<std::string> const& args) std::vector<std::string> resource_compile; std::vector<std::string>* pArgTgt = &preprocess; for (std::string const& arg : cmMakeRange(args).advance(4)) { - if (arg == "--") { + // We use ++ as seperator between the preprocessing step definition and the + // rc compilation step becase we need to prepend a -- to seperate the + // source file properly from other options when using clang-cl for + // preprocessing. + if (arg == "++") { pArgTgt = &resource_compile; } else { if (arg.find("SOURCE_DIR") != std::string::npos) { diff --git a/Source/kwsys/CTestConfig.cmake b/Source/kwsys/CTestConfig.cmake index 33ea84c..12347b6 100644 --- a/Source/kwsys/CTestConfig.cmake +++ b/Source/kwsys/CTestConfig.cmake @@ -3,7 +3,9 @@ set(CTEST_PROJECT_NAME "KWSys") set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT") -set(CTEST_DROP_METHOD "http") +if (NOT CTEST_DROP_METHOD STREQUAL "https") + set(CTEST_DROP_METHOD "http") +endif () set(CTEST_DROP_SITE "open.cdash.org") set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard") set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx index 5452f73..c6d4b19 100644 --- a/Source/kwsys/Glob.cxx +++ b/Source/kwsys/Glob.cxx @@ -27,7 +27,7 @@ #include <cstdio> #include <cstring> namespace KWSYS_NAMESPACE { -#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__) +#if defined(_WIN32) || defined(__APPLE__) // On Windows and Apple, no difference between lower and upper case # define KWSYS_GLOB_CASE_INDEPENDENT #endif diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in index b5a34d5..e8474e2 100644 --- a/Source/kwsys/Glob.hxx.in +++ b/Source/kwsys/Glob.hxx.in @@ -126,8 +126,8 @@ protected: bool RecurseListDirs; private: - Glob(const Glob&); // Not implemented. - void operator=(const Glob&); // Not implemented. + Glob(const Glob&) = delete; + void operator=(const Glob&) = delete; }; } // namespace @KWSYS_NAMESPACE@ diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index cc45529..e1e7721 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -2128,17 +2128,17 @@ static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int sig, #endif #ifdef SIGABRT case SIGABRT: - KWSYSPE_CASE(Other, "Child aborted"); + KWSYSPE_CASE(Other, "Subprocess aborted"); break; #endif #ifdef SIGKILL case SIGKILL: - KWSYSPE_CASE(Other, "Child killed"); + KWSYSPE_CASE(Other, "Subprocess killed"); break; #endif #ifdef SIGTERM case SIGTERM: - KWSYSPE_CASE(Other, "Child terminated"); + KWSYSPE_CASE(Other, "Subprocess terminated"); break; #endif #ifdef SIGHUP diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index ed1cdc0..9c34a56 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -863,7 +863,7 @@ void SystemInformation::RunMemoryCheck() // Hide implementation details in an anonymous namespace. namespace { // ***************************************************************************** -#if defined(__linux) || defined(__APPLE__) +#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) int LoadLines(FILE* file, std::vector<std::string>& lines) { // Load each line in the given file into a the vector. @@ -893,7 +893,7 @@ int LoadLines(FILE* file, std::vector<std::string>& lines) return nRead; } -# if defined(__linux) +# if defined(__linux) || defined(__CYGWIN__) // ***************************************************************************** int LoadLines(const char* fileName, std::vector<std::string>& lines) { @@ -926,7 +926,7 @@ int NameValue(std::vector<std::string> const& lines, std::string const& name, } #endif -#if defined(__linux) +#if defined(__linux) || defined(__CYGWIN__) // **************************************************************************** template <typename T> int GetFieldsFromFile(const char* fileName, const char** fieldNames, T* values) @@ -3393,7 +3393,7 @@ bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() pos = buffer.find("processor\t", pos + 1); } -#ifdef __linux +#if defined(__linux) || defined(__CYGWIN__) // Count sockets. std::set<int> PhysicalIDs; std::string idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id"); @@ -3414,8 +3414,8 @@ bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() this->NumberOfPhysicalCPU = NumberOfCoresPerSocket * (unsigned int)NumberOfSockets; -#else // __CYGWIN__ - // does not have "physical id" entries, neither "cpu cores" +#else + // For systems which do not have "physical id" entries, neither "cpu cores" // this has to be fixed for hyper-threading. std::string cpucount = this->ExtractValueFromCpuInfoFile(buffer, "cpu count"); @@ -3597,7 +3597,7 @@ long long SystemInformationImplementation::GetHostMemoryTotal() GlobalMemoryStatusEx(&statex); return statex.ullTotalPhys / 1024; # endif -#elif defined(__linux) +#elif defined(__linux) || defined(__CYGWIN__) long long memTotal = 0; int ierr = GetFieldFromFile("/proc/meminfo", "MemTotal:", memTotal); if (ierr) { @@ -3712,6 +3712,16 @@ long long SystemInformationImplementation::GetHostMemoryUsed() GlobalMemoryStatusEx(&statex); return (statex.ullTotalPhys - statex.ullAvailPhys) / 1024; # endif +#elif defined(__CYGWIN__) + const char* names[3] = { "MemTotal:", "MemFree:", nullptr }; + long long values[2] = { 0 }; + int ierr = GetFieldsFromFile("/proc/meminfo", names, values); + if (ierr) { + return ierr; + } + long long& memTotal = values[0]; + long long& memFree = values[1]; + return memTotal - memFree; #elif defined(__linux) // First try to use MemAvailable, but it only works on newer kernels const char* names2[3] = { "MemTotal:", "MemAvailable:", nullptr }; @@ -3773,7 +3783,7 @@ long long SystemInformationImplementation::GetProcMemoryUsed() return -2; } return pmc.WorkingSetSize / 1024; -#elif defined(__linux) +#elif defined(__linux) || defined(__CYGWIN__) long long memUsed = 0; int ierr = GetFieldFromFile("/proc/self/status", "VmRSS:", memUsed); if (ierr) { @@ -3850,7 +3860,8 @@ long long SystemInformationImplementation::GetProcessId() #if defined(_WIN32) return GetCurrentProcessId(); #elif defined(__linux) || defined(__APPLE__) || defined(__OpenBSD__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(__CYGWIN__) return getpid(); #else return -1; diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 25705ea..6144d9c 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -96,19 +96,12 @@ # if defined(_MSC_VER) && _MSC_VER >= 1800 # define KWSYS_WINDOWS_DEPRECATED_GetVersionEx # endif -#elif defined(__CYGWIN__) -# include <windows.h> -# undef _WIN32 #endif #if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H extern char** environ; #endif -#ifdef __CYGWIN__ -# include <sys/cygwin.h> -#endif - // getpwnam doesn't exist on Windows and Cray Xt3/Catamount // same for TIOCGWINSZ #if defined(_WIN32) || defined(__LIBCATAMOUNT__) || \ @@ -1290,15 +1283,7 @@ bool SystemTools::PathExists(const std::string& path) if (path.empty()) { return false; } -#if defined(__CYGWIN__) - // Convert path to native windows path if possible. - char winpath[MAX_PATH]; - if (SystemTools::PathCygwinToWin32(path.c_str(), winpath)) { - return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES); - } - struct stat st; - return lstat(path.c_str(), &st) == 0; -#elif defined(_WIN32) +#if defined(_WIN32) return (GetFileAttributesW(Encoding::ToWindowsExtendedPath(path).c_str()) != INVALID_FILE_ATTRIBUTES); #else @@ -1320,14 +1305,7 @@ bool SystemTools::FileExists(const std::string& filename) if (filename.empty()) { return false; } -#if defined(__CYGWIN__) - // Convert filename to native windows path if possible. - char winpath[MAX_PATH]; - if (SystemTools::PathCygwinToWin32(filename.c_str(), winpath)) { - return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES); - } - return access(filename.c_str(), R_OK) == 0; -#elif defined(_WIN32) +#if defined(_WIN32) DWORD attr = GetFileAttributesW(Encoding::ToWindowsExtendedPath(filename).c_str()); if (attr == INVALID_FILE_ATTRIBUTES) { @@ -1433,27 +1411,9 @@ int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf) #endif } -#ifdef __CYGWIN__ -bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path) -{ - 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; - } - SystemToolsStatics->Cyg2Win32Map.insert( - SystemToolsStatic::StringMap::value_type(path, win32_path)); - } - return win32_path[0] != 0; -} -#endif - bool SystemTools::Touch(const std::string& filename, bool create) { - if (!SystemTools::PathExists(filename)) { + if (!SystemTools::FileExists(filename)) { if (create) { FILE* file = Fopen(filename, "a+b"); if (file) { diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index 5dbb726..74dc176 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -331,15 +331,6 @@ public: static int Stat(const char* path, Stat_t* buf); static int Stat(const std::string& path, Stat_t* buf); -/** - * Converts Cygwin path to Win32 path. Uses dictionary container for - * caching and calls to cygwin_conv_to_win32_path from Cygwin dll - * for actual translation. Returns true on success, else false. - */ -#ifdef __CYGWIN__ - static bool PathCygwinToWin32(const char* path, char* win32_path); -#endif - /** * Return file length */ diff --git a/Source/kwsys/testProcess.c b/Source/kwsys/testProcess.c index 0c658f5..eed770c 100644 --- a/Source/kwsys/testProcess.c +++ b/Source/kwsys/testProcess.c @@ -450,24 +450,25 @@ static int runChild2(kwsysProcess* kp, const char* cmd[], int state, printf("The process is still executing.\n"); break; case kwsysProcess_State_Expired: - printf("Child was killed when timeout expired.\n"); + printf("Subprocess was killed when timeout expired.\n"); break; case kwsysProcess_State_Exited: - printf("Child exited with value = %d\n", kwsysProcess_GetExitValue(kp)); + printf("Subprocess exited with value = %d\n", + kwsysProcess_GetExitValue(kp)); result = ((exception != kwsysProcess_GetExitException(kp)) || (value != kwsysProcess_GetExitValue(kp))); break; case kwsysProcess_State_Killed: - printf("Child was killed by parent.\n"); + printf("Subprocess was killed by parent.\n"); break; case kwsysProcess_State_Exception: - printf("Child terminated abnormally: %s\n", + printf("Subprocess terminated abnormally: %s\n", kwsysProcess_GetExceptionString(kp)); result = ((exception != kwsysProcess_GetExitException(kp)) || (value != kwsysProcess_GetExitValue(kp))); break; case kwsysProcess_State_Disowned: - printf("Child was disowned.\n"); + printf("Subprocess was disowned.\n"); break; case kwsysProcess_State_Error: printf("Error in administrating child process: [%s]\n", diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index 1d34614..cfa420d 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -422,6 +422,28 @@ static bool CheckFileOperations() res = false; } +#if !defined(_WIN32) + std::string const testBadSymlink(testNewDir + "/badSymlink.txt"); + std::string const testBadSymlinkTgt(testNewDir + "/missing/symlinkTgt.txt"); + if (!kwsys::SystemTools::CreateSymlink(testBadSymlinkTgt, testBadSymlink)) { + std::cerr << "Problem with CreateSymlink for: " << testBadSymlink << " -> " + << testBadSymlinkTgt << std::endl; + res = false; + } + + if (!kwsys::SystemTools::Touch(testBadSymlink, false)) { + std::cerr << "Problem with Touch (no create) for: " << testBadSymlink + << std::endl; + res = false; + } +#endif + + if (!kwsys::SystemTools::Touch(testNewDir, false)) { + std::cerr << "Problem with Touch (no create) for: " << testNewDir + << std::endl; + res = false; + } + kwsys::SystemTools::Touch(testNewFile, true); if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) { std::cerr << "Problem with RemoveADirectory for: " << testNewDir |