diff options
Diffstat (limited to 'Source')
115 files changed, 3174 insertions, 2349 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 9c3df38..a015db9 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 0) +set(CMake_VERSION_PATCH 20200721) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) 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..53be4fe 100644 --- a/Source/CPack/cmCPackExternalGenerator.cxx +++ b/Source/CPack/cmCPackExternalGenerator.cxx @@ -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; diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index 288dc58..c641175 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -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="); } @@ -333,7 +350,8 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( 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")) { @@ -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); @@ -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"); @@ -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; } diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 85b8ab1..d2772a7 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; @@ -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,118 @@ 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,]+", + // racecheck + "== .* (Potential .* hazard detected)", "== .* (Race reported)", + // synccheck + "== (Barrier error)", + // initcheck + "== (Uninitialized .* memory read)", "== (Unused memory)", + // 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/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/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 b1f4a82..659a512 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; @@ -334,11 +328,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 @@ -348,9 +338,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; @@ -367,11 +355,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, @@ -497,8 +481,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())) { @@ -658,20 +641,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/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/cmCTest.cxx b/Source/cmCTest.cxx index bca7540..4254e2e 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -841,6 +841,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, 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/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 4c5f57d..fbb95e1 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); @@ -841,7 +841,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 +849,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 +903,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 +912,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 +924,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 +963,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 +981,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 +1687,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 +1734,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 +1742,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) { @@ -1823,8 +1822,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 +1831,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..6b4d110 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -196,7 +196,7 @@ 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); 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..8465c58 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; 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/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..be22ad4 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -236,9 +236,8 @@ 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")); + const bool excludeExternal = it.second[0]->GetMakefile()->IsOn( + "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES"); if (!splitted.empty() && (!excludeExternal || (relative.find("..") == std::string::npos)) && relative.find("CMakeFiles") == std::string::npos) { @@ -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/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..e9af208 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)); } @@ -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/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..345f0ba 100644 --- a/Source/cmGeneratedFileStream.cxx +++ b/Source/cmGeneratedFileStream.cxx @@ -122,10 +122,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 +223,8 @@ void cmGeneratedFileStream::SetName(const std::string& fname) { this->Name = fname; } + +void cmGeneratedFileStream::SetTempExt(std::string const& ext) +{ + this->TempExt = ext; +} diff --git a/Source/cmGeneratedFileStream.h b/Source/cmGeneratedFileStream.h index a9088ac..3dee142 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,12 @@ 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); }; #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..a1a0ae8 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(), @@ -1703,12 +1711,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 +1724,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 +1749,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 f2011ee..4fe68d2 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 \"" @@ -801,7 +802,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 +815,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 +853,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 +948,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 { @@ -1137,7 +1193,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,6 +1365,9 @@ void AddSwiftImplicitIncludeDirectories( for (const cmLinkImplItem& library : libraries->Libraries) { if (const cmGeneratorTarget* dependency = library.Target) { + if (dependency->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + continue; + } if (cm::contains(dependency->GetAllConfigCompileLanguages(), "Swift")) { EvaluatedTargetPropertyEntry entry{ library, library.Backtrace }; @@ -1723,8 +1782,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; @@ -1784,12 +1843,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"; } @@ -2236,7 +2295,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 = @@ -2757,7 +2816,7 @@ cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target) if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) { std::set<cmSourceFile*> emitted; std::vector<std::string> const& configs = - this->Makefile->GetGeneratorConfigs(); + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); for (std::string const& c : configs) { std::vector<cmSourceFile*> sources; this->GeneratorTarget->GetSourceFiles(sources, c); @@ -2968,7 +3027,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); } @@ -4408,12 +4467,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; } @@ -5291,8 +5413,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 <> @@ -5306,8 +5427,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 <> @@ -5321,7 +5441,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> @@ -5722,7 +5842,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 = @@ -6731,7 +6851,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; @@ -6855,7 +6975,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 @@ -6920,7 +7040,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; diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 3aedbf5..08aa015 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -148,6 +148,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 +175,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 +525,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 +1053,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/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index 358d65a..1589c47 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -550,9 +550,9 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj) */ for (auto& sg : groupFilesList) { std::ostream* fout; - bool useProjectFile = cmIsOn(*this->GeneratorTarget->GetProperty( - "GHS_NO_SOURCE_GROUP_FILE")) || - 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/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 4dc4092..49b73a8 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -304,28 +304,21 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const for (const auto& target : localGen->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET || target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY || - target->GetType() == cmStateEnums::TargetType::UTILITY) { + target->GetType() == cmStateEnums::TargetType::UTILITY || + 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<std::string> configs = + target->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); 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; - } + for (std::string const& config : configs) { + target->GetSourceFiles(srcs, config); + if (!srcs.empty()) { + break; } } + if (srcs.empty()) { std::ostringstream e; e << "No SOURCES given to target: " << target->GetName(); @@ -349,7 +342,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( @@ -376,14 +370,10 @@ bool cmGlobalGenerator::CheckTargetsForPchCompilePdb() const for (const auto& target : generator->GetGeneratorTargets()) { if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET || target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY || - target->GetType() == cmStateEnums::TargetType::UTILITY) { + target->GetType() == cmStateEnums::TargetType::UTILITY || + 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"); @@ -596,6 +586,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 +667,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 @@ -1442,12 +1437,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; @@ -1698,8 +1691,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 +1981,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 += " && "; @@ -3123,7 +3117,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 +3217,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/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index d36adfb..2fcba9a 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -470,8 +470,7 @@ void cmGlobalGhsMultiGenerator::WriteAllTarget( if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) { continue; } - cmProp p = t->GetProperty("EXCLUDE_FROM_ALL"); - if (!(p && cmIsOn(*p))) { + if (!cmIsOn(t->GetProperty("EXCLUDE_FROM_ALL"))) { defaultTargets.push_back(t); } } @@ -635,7 +634,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..48eb405 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); } @@ -1207,7 +1208,8 @@ void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias, 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; } } @@ -1280,7 +1282,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) { @@ -1339,11 +1342,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; @@ -1538,7 +1539,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 +1714,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 +1809,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 +2489,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 +2530,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 +2573,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 +2586,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/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..c851eea 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -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/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index c688da2..b31d069 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -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 a5ce5d1..e54de5d 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -12,6 +12,7 @@ #include <cm/memory> #include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/RegularExpression.hxx" @@ -172,6 +173,7 @@ cmGlobalXCodeGenerator::cmGlobalXCodeGenerator( this->RootObject = nullptr; this->MainGroupChildren = nullptr; + this->FrameworkGroup = nullptr; this->CurrentMakefile = nullptr; this->CurrentLocalGenerator = nullptr; this->XcodeBuildCommandInitialized = false; @@ -271,6 +273,13 @@ std::string cmGlobalXCodeGenerator::FindXcodeBuildCommand() return makeProgram; } +bool cmGlobalXCodeGenerator::SetSystemName(std::string const& s, + cmMakefile* mf) +{ + this->SystemName = s; + return this->cmGlobalGenerator::SetSystemName(s, mf); +} + bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts, bool build, cmMakefile* mf) { @@ -468,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); @@ -665,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) @@ -733,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) { @@ -819,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)); @@ -861,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", @@ -914,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"; @@ -931,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"; @@ -965,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 // { @@ -981,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) { @@ -1005,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; } @@ -1069,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 @@ -1144,23 +1214,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(); @@ -1168,16 +1239,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); } @@ -1267,7 +1341,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) { @@ -1315,7 +1389,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) { @@ -1345,22 +1419,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); @@ -2760,6 +2832,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) { { @@ -2787,21 +3043,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: @@ -2812,15 +3067,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) { @@ -3001,6 +3263,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); @@ -3035,6 +3298,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"); @@ -3111,6 +3383,14 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( if (archs.empty()) { // Tell Xcode to use NATIVE_ARCH instead of ARCHS. buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("YES")); + // When targeting macOS, use only the host architecture. + if (this->SystemName == "Darwin"_s && + (!sysroot || !*sysroot || + cmSystemTools::LowerCase(sysroot).find("macos") != + std::string::npos)) { + buildSettings->AddAttribute("ARCHS", + this->CreateString("$(NATIVE_ARCH_ACTUAL)")); + } } else { // Tell Xcode to use ARCHS (ONLY_ACTIVE_ARCH defaults to NO). buildSettings->AddAttribute("ARCHS", this->CreateString(archs)); @@ -3142,6 +3422,12 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( std::string symroot = cmStrCat(root->GetCurrentBinaryDirectory(), "/build"); buildSettings->AddAttribute("SYMROOT", this->CreateString(symroot)); + // Inside a try_compile project, do not require signing on any platform. + if (this->CMakeInstance->GetIsInTryCompile()) { + buildSettings->AddAttribute("CODE_SIGNING_ALLOWED", + this->CreateString("NO")); + } + for (auto& config : configs) { cmXCodeObject* buildSettingsForCfg = this->CreateFlatClone(buildSettings); @@ -3210,7 +3496,8 @@ void cmGlobalXCodeGenerator::ComputeArchitectures(cmMakefile* mf) } if (this->Architectures.empty()) { - // With no ARCHS we use ONLY_ACTIVE_ARCH. + // With no ARCHS we use ONLY_ACTIVE_ARCH and possibly a + // platform-specific default ARCHS placeholder value. // Look up the arch that Xcode chooses in this case. if (const char* arch = mf->GetDefinition("CMAKE_XCODE_ARCHS")) { this->ObjectDirArchDefault = arch; diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index e380f1c..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 { @@ -109,6 +109,7 @@ public: bool ShouldStripResourcePath(cmMakefile*) const override; + bool SetSystemName(std::string const& s, cmMakefile* mf) override; bool SetGeneratorToolset(std::string const& ts, bool build, cmMakefile* mf) override; void AppendFlag(std::string& flags, std::string const& flag) const; @@ -203,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, @@ -281,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; @@ -294,12 +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/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 178af73..ddd6c22 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)) { 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 3b3f110..fe0d0a7 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"); @@ -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); } @@ -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,11 +754,8 @@ 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(); @@ -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" }, @@ -803,39 +798,8 @@ 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"); - } + for (std::string const& c : configNames) { + target->ComputeCompileFeatures(c, inferredEnabledLanguages); } } } @@ -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)); } @@ -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 += " "; } @@ -2007,7 +1971,7 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags, // 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 +2010,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 +2153,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"; - - 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()) { + cmStandardLevelResolver standardResolver(this->Makefile); - 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 +2411,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 @@ -3292,8 +3117,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, @@ -3305,7 +3130,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(); } @@ -3846,8 +3671,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()) { @@ -3877,7 +3701,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( @@ -3886,8 +3710,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()) { @@ -3913,7 +3736,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/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 87e8aa4..aee7f45 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -668,7 +668,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/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index de1461a..86a888a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -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(); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 5d50e2d..ad61ad3 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -1331,8 +1331,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 +1580,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; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index db5cee9..aca40fa 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -34,6 +34,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 +69,8 @@ class cmMessenger; +using namespace cmFSPermissions; + cmDirectoryId::cmDirectoryId(std::string s) : String(std::move(s)) { @@ -82,7 +85,6 @@ cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator, { this->IsSourceFileTryCompile = false; - this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused(); this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars(); this->SuppressSideEffects = false; @@ -750,7 +752,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 +1435,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 +1514,6 @@ void cmMakefile::PopFunctionScope(bool reportError) #endif this->PopLoopBlockBarrier(); - - this->CheckForUnusedVariables(); } void cmMakefile::PushMacroScope(std::string const& fileName, @@ -1661,7 +1660,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 +1860,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 +1920,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 +1947,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 +2521,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 +3252,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 +3693,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 +3712,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 +3966,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 +3990,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 +4005,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 +4062,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 +4115,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 +4227,6 @@ void cmMakefile::PopScope() this->PopLoopBlockBarrier(); - this->CheckForUnusedVariables(); - this->PopSnapshot(); } @@ -4557,7 +4542,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 +4584,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 +4600,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 +4637,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..286a3dc 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -197,8 +197,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 +531,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 +806,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 +821,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,11 +831,11 @@ 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"); @@ -839,16 +845,16 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( 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 +881,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( { const char* val = this->LocalGenerator->GetRuleLauncher( this->GeneratorTarget, "RULE_LAUNCH_COMPILE"); - if (val && *val) { + if (cmNonempty(val)) { launcher = cmStrCat(val, ' '); } } diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index b92548f..de68371 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, ' '); } @@ -733,8 +733,13 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement( static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) - globalGen->GetRuleCmdLength(this->LanguageLinkerDeviceRule(config)); - build.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") + - genTarget->GetName() + ".rsp"); + std::string path = localGen.GetHomeRelativeOutputPath(); + if (!path.empty()) { + path += '/'; + } + build.RspFile = this->ConvertToNinjaPath( + cmStrCat(path, "CMakeFiles/", genTarget->GetName(), + globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp")); // Gather order-only dependencies. this->GetLocalGenerator()->AppendTargetDepends( @@ -1154,8 +1159,13 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( globalGen->GetRuleCmdLength(linkBuild.Rule); } - linkBuild.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") + - gt->GetName() + ".rsp"); + std::string path = localGen.GetHomeRelativeOutputPath(); + if (!path.empty()) { + path += '/'; + } + linkBuild.RspFile = this->ConvertToNinjaPath( + cmStrCat(path, "CMakeFiles/", gt->GetName(), + globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp")); // Gather order-only dependencies. this->GetLocalGenerator()->AppendTargetDepends(gt, linkBuild.OrderOnlyDeps, diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index d406c99..de18536 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -65,7 +65,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 +189,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 +662,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 +813,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 +828,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,11 +839,11 @@ 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")); @@ -843,17 +853,16 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, 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/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..bba8b03 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -320,7 +320,10 @@ 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) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ @@ -396,12 +399,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/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 511a018..218bd4c 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)); } } @@ -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) { @@ -1611,7 +1610,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/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..0eb869c --- /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 (!defaultStd || !*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 (!featuresKnown || !*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/cmStandardLexer.h b/Source/cmStandardLexer.h index cc67ac2..e0b2116 100644 --- a/Source/cmStandardLexer.h +++ b/Source/cmStandardLexer.h @@ -3,6 +3,10 @@ #ifndef cmStandardLexer_h #define cmStandardLexer_h +#if defined(__linux) +/* Needed for glibc < 2.12 */ +# define _XOPEN_SOURCE 600 +#endif #if !defined(_WIN32) && !defined(__sun) /* POSIX APIs are needed */ # define _POSIX_C_SOURCE 200809L 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/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..aec9afa 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; @@ -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) { @@ -598,6 +600,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 +672,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; @@ -1127,6 +1169,11 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) 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 +1357,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); } @@ -1413,6 +1469,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 +1687,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 +1712,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 +1735,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 +1884,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 @@ -1865,7 +1944,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 +1985,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..7a16de8 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -209,6 +209,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 +236,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/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index e10a8e2..7c0ce71 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -102,7 +102,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); diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index a3ccd2b..5d9199b 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; @@ -333,6 +335,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,7 +436,7 @@ void cmVisualStudio10TargetGenerator::Generate() e1.Attribute("Label", "Globals"); e1.Element("ProjectGuid", "{" + this->GUID + "}"); - if (this->MSTools && + if ((this->MSTools || this->Android) && this->GeneratorTarget->GetType() <= cmStateEnums::GLOBAL_TARGET) { this->WriteApplicationTypeSettings(e1); this->VerifyNecessaryFiles(); @@ -469,7 +478,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); } @@ -658,7 +671,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,9 +1147,11 @@ 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"; } @@ -1166,6 +1181,8 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues(Elem& e0) } } else if (this->NsightTegra) { this->WriteNsightTegraConfigurationValues(e1, c); + } else if (this->Android) { + this->WriteAndroidConfigurationValues(e1, c); } } } @@ -1324,6 +1341,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 +1976,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 +1985,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; } } @@ -2909,7 +2944,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)) { @@ -4015,8 +4052,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); } } @@ -4131,8 +4167,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"); } @@ -4348,6 +4385,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", @@ -4385,13 +4423,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..45fa44b 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 @@ -101,16 +97,13 @@ #if !defined(CMAKE_BOOTSTRAP) # 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 +194,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 +773,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 +1129,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 +1371,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()) { @@ -1499,10 +1487,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)); @@ -1970,6 +1958,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 +1978,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); } } @@ -2743,9 +2742,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..7c66c5c 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> @@ -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..1a5fea1 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; @@ -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 |