diff options
Diffstat (limited to 'Source')
25 files changed, 531 insertions, 168 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 7915a9c..8018e40 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 20) -set(CMake_VERSION_PATCH 20210608) +set(CMake_VERSION_PATCH 20210610) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 5a6c775..a892113 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -40,6 +40,22 @@ void cmCTestRunTest::CheckOutput(std::string const& line) { cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex() << ": " << line << std::endl); + + // Check for special CTest XML tags in this line of output. + // If any are found, this line is excluded from ProcessOutput. + if (!line.empty() && line.find("<CTest") != std::string::npos) { + if (this->TestHandler->CustomCompletionStatusRegex.find(line)) { + this->TestResult.CustomCompletionStatus = + this->TestHandler->CustomCompletionStatusRegex.match(1); + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + this->GetIndex() << ": " + << "Test Details changed to '" + << this->TestResult.CustomCompletionStatus + << "'" << std::endl); + return; + } + } + this->ProcessOutput += line; this->ProcessOutput += "\n"; diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 1596d4a..730ec0f 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -308,6 +308,10 @@ cmCTestTestHandler::cmCTestTestHandler() // regex to detect each individual <DartMeasurement>...</DartMeasurement> this->DartStuff1.compile( "(<DartMeasurement[^<]*</DartMeasurement[a-zA-Z]*>)"); + + // regex to detect <CTestDetails>...</CTestDetails> + this->CustomCompletionStatusRegex.compile( + "<CTestDetails>(.*)</CTestDetails>"); } void cmCTestTestHandler::Initialize() @@ -1460,7 +1464,11 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml) xml.StartElement("NamedMeasurement"); xml.Attribute("type", "text/string"); xml.Attribute("name", "Completion Status"); - xml.Element("Value", result.CompletionStatus); + if (result.CustomCompletionStatus.empty()) { + xml.Element("Value", result.CompletionStatus); + } else { + xml.Element("Value", result.CustomCompletionStatus); + } xml.EndElement(); // NamedMeasurement xml.StartElement("NamedMeasurement"); @@ -1550,19 +1558,29 @@ void cmCTestTestHandler::AttachFiles(cmXMLWriter& xml, result.Properties->AttachOnFail.end()); } for (std::string const& file : result.Properties->AttachedFiles) { - const std::string& base64 = this->CTest->Base64GzipEncodeFile(file); - std::string const fname = cmSystemTools::GetFilenameName(file); - xml.StartElement("NamedMeasurement"); - xml.Attribute("name", "Attached File"); - xml.Attribute("encoding", "base64"); - xml.Attribute("compression", "tar/gzip"); - xml.Attribute("filename", fname); - xml.Attribute("type", "file"); - xml.Element("Value", base64); - xml.EndElement(); // NamedMeasurement + this->AttachFile(xml, file, ""); } } +void cmCTestTestHandler::AttachFile(cmXMLWriter& xml, std::string const& file, + std::string const& name) +{ + const std::string& base64 = this->CTest->Base64GzipEncodeFile(file); + std::string const fname = cmSystemTools::GetFilenameName(file); + xml.StartElement("NamedMeasurement"); + std::string measurement_name = name; + if (measurement_name.empty()) { + measurement_name = "Attached File"; + } + xml.Attribute("name", measurement_name); + xml.Attribute("encoding", "base64"); + xml.Attribute("compression", "tar/gzip"); + xml.Attribute("filename", fname); + xml.Attribute("type", "file"); + xml.Element("Value", base64); + xml.EndElement(); // NamedMeasurement +} + int cmCTestTestHandler::ExecuteCommands(std::vector<std::string>& vec) { for (std::string const& it : vec) { @@ -2041,11 +2059,11 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, cmCTest::CleanString(measurementfile.match(5)); if (cmSystemTools::FileExists(filename)) { long len = cmSystemTools::FileLength(filename); + std::string k1 = measurementfile.match(1); + std::string v1 = measurementfile.match(2); + std::string k2 = measurementfile.match(3); + std::string v2 = measurementfile.match(4); if (len == 0) { - std::string k1 = measurementfile.match(1); - std::string v1 = measurementfile.match(2); - std::string k2 = measurementfile.match(3); - std::string v2 = measurementfile.match(4); if (cmSystemTools::LowerCase(k1) == "type") { v1 = "text/string"; } @@ -2060,35 +2078,53 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, xml.Element("Value", "Image " + filename + " is empty"); xml.EndElement(); } else { - cmsys::ifstream ifs(filename.c_str(), - std::ios::in + std::string type; + std::string name; + if (cmSystemTools::LowerCase(k1) == "type") { + type = v1; + } else if (cmSystemTools::LowerCase(k2) == "type") { + type = v2; + } + if (cmSystemTools::LowerCase(k1) == "name") { + name = v1; + } else if (cmSystemTools::LowerCase(k2) == "name") { + name = v2; + } + if (type == "file") { + // Treat this measurement like an "ATTACHED_FILE" when the type + // is explicitly "file" (not an image). + this->AttachFile(xml, filename, name); + } else { + cmsys::ifstream ifs(filename.c_str(), + std::ios::in #ifdef _WIN32 - | std::ios::binary + | std::ios::binary #endif - ); - auto file_buffer = cm::make_unique<unsigned char[]>(len + 1); - ifs.read(reinterpret_cast<char*>(file_buffer.get()), len); - auto encoded_buffer = cm::make_unique<unsigned char[]>( - static_cast<int>(static_cast<double>(len) * 1.5 + 5.0)); - - size_t rlen = cmsysBase64_Encode(file_buffer.get(), len, - encoded_buffer.get(), 1); - - xml.StartElement("NamedMeasurement"); - xml.Attribute(measurementfile.match(1).c_str(), - measurementfile.match(2)); - xml.Attribute(measurementfile.match(3).c_str(), - measurementfile.match(4)); - xml.Attribute("encoding", "base64"); - std::ostringstream ostr; - for (size_t cc = 0; cc < rlen; cc++) { - ostr << encoded_buffer[cc]; - if (cc % 60 == 0 && cc) { - ostr << std::endl; + ); + auto file_buffer = cm::make_unique<unsigned char[]>(len + 1); + ifs.read(reinterpret_cast<char*>(file_buffer.get()), len); + auto encoded_buffer = cm::make_unique<unsigned char[]>( + static_cast<int>(static_cast<double>(len) * 1.5 + 5.0)); + + size_t rlen = cmsysBase64_Encode(file_buffer.get(), len, + encoded_buffer.get(), 1); + + xml.StartElement("NamedMeasurement"); + xml.Attribute(measurementfile.match(1).c_str(), + measurementfile.match(2)); + xml.Attribute(measurementfile.match(3).c_str(), + measurementfile.match(4)); + xml.Attribute("encoding", "base64"); + std::ostringstream ostr; + for (size_t cc = 0; cc < rlen; cc++) { + ostr << encoded_buffer[cc]; + if (cc % 60 == 0 && cc) { + ostr << std::endl; + } } + xml.Element("Value", ostr.str()); + xml.EndElement(); // NamedMeasurement } - xml.Element("Value", ostr.str()); - xml.EndElement(); // NamedMeasurement } } else { int idx = 4; diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index 6841624..bd51738 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -175,6 +175,7 @@ public: std::string ExceptionStatus; bool CompressOutput; std::string CompletionStatus; + std::string CustomCompletionStatus; std::string Output; std::string DartString; int TestCount; @@ -237,6 +238,8 @@ protected: cmCTestTestResult const& result); // Write attached test files into the xml void AttachFiles(cmXMLWriter& xml, cmCTestTestResult& result); + void AttachFile(cmXMLWriter& xml, std::string const& file, + std::string const& name); //! Clean test output to specified length void CleanTestOutput(std::string& output, size_t length); @@ -356,6 +359,7 @@ private: ListOfTests TestList; size_t TotalNumberOfTests; cmsys::RegularExpression DartStuff; + cmsys::RegularExpression CustomCompletionStatusRegex; std::ostream* LogFile; diff --git a/Source/LexerParser/cmFortranParser.cxx b/Source/LexerParser/cmFortranParser.cxx index 0ea3d97..3f3ddde 100644 --- a/Source/LexerParser/cmFortranParser.cxx +++ b/Source/LexerParser/cmFortranParser.cxx @@ -599,13 +599,13 @@ static const yytype_int8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 99, 99, 99, 102, 106, 111, 120, 126, 133, - 138, 142, 147, 155, 160, 165, 170, 175, 180, 185, - 190, 195, 199, 203, 207, 211, 212, 217, 217, 217, - 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, - 223, 223, 224, 224, 225, 225, 226, 226, 229, 230, - 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245 + 0, 101, 101, 101, 104, 108, 113, 122, 128, 135, + 140, 144, 149, 157, 162, 167, 172, 177, 182, 187, + 192, 197, 201, 205, 209, 213, 214, 219, 219, 219, + 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, + 225, 225, 226, 226, 227, 227, 228, 228, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247 }; #endif @@ -1364,7 +1364,29 @@ yydestruct (const char *yymsg, YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YY_USE (yykind); + switch (yykind) + { + case YYSYMBOL_STRING: /* STRING */ +#line 95 "cmFortranParser.y" + { free(((*yyvaluep).string)); } +#line 1373 "cmFortranParser.cxx" + break; + + case YYSYMBOL_WORD: /* WORD */ +#line 95 "cmFortranParser.y" + { free(((*yyvaluep).string)); } +#line 1379 "cmFortranParser.cxx" + break; + + case YYSYMBOL_CPP_INCLUDE_ANGLE: /* CPP_INCLUDE_ANGLE */ +#line 95 "cmFortranParser.y" + { free(((*yyvaluep).string)); } +#line 1385 "cmFortranParser.cxx" + break; + + default: + break; + } YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -1634,26 +1656,26 @@ yyreduce: switch (yyn) { case 4: /* stmt: INTERFACE EOSTMT */ -#line 102 "cmFortranParser.y" +#line 104 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_SetInInterface(parser, true); } -#line 1643 "cmFortranParser.cxx" +#line 1665 "cmFortranParser.cxx" break; case 5: /* stmt: USE WORD other EOSTMT */ -#line 106 "cmFortranParser.y" +#line 108 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleUse(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1653 "cmFortranParser.cxx" +#line 1675 "cmFortranParser.cxx" break; case 6: /* stmt: MODULE WORD other EOSTMT */ -#line 111 "cmFortranParser.y" +#line 113 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); if (cmsysString_strcasecmp((yyvsp[-2].string), "function") != 0 && @@ -1663,22 +1685,22 @@ yyreduce: } free((yyvsp[-2].string)); } -#line 1667 "cmFortranParser.cxx" +#line 1689 "cmFortranParser.cxx" break; case 7: /* stmt: SUBMODULE LPAREN WORD RPAREN WORD other EOSTMT */ -#line 120 "cmFortranParser.y" +#line 122 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleSubmodule(parser, (yyvsp[-4].string), (yyvsp[-2].string)); free((yyvsp[-4].string)); free((yyvsp[-2].string)); } -#line 1678 "cmFortranParser.cxx" +#line 1700 "cmFortranParser.cxx" break; case 8: /* stmt: SUBMODULE LPAREN WORD COLON WORD RPAREN WORD other EOSTMT */ -#line 126 "cmFortranParser.y" +#line 128 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleSubmoduleNested(parser, (yyvsp[-6].string), (yyvsp[-4].string), (yyvsp[-2].string)); @@ -1686,40 +1708,40 @@ yyreduce: free((yyvsp[-4].string)); free((yyvsp[-2].string)); } -#line 1690 "cmFortranParser.cxx" +#line 1712 "cmFortranParser.cxx" break; case 9: /* stmt: INTERFACE WORD other EOSTMT */ -#line 133 "cmFortranParser.y" +#line 135 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_SetInInterface(parser, true); free((yyvsp[-2].string)); } -#line 1700 "cmFortranParser.cxx" +#line 1722 "cmFortranParser.cxx" break; case 10: /* stmt: END INTERFACE other EOSTMT */ -#line 138 "cmFortranParser.y" +#line 140 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_SetInInterface(parser, false); } -#line 1709 "cmFortranParser.cxx" +#line 1731 "cmFortranParser.cxx" break; case 11: /* stmt: USE DCOLON WORD other EOSTMT */ -#line 142 "cmFortranParser.y" +#line 144 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleUse(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1719 "cmFortranParser.cxx" +#line 1741 "cmFortranParser.cxx" break; case 12: /* stmt: USE COMMA WORD DCOLON WORD other EOSTMT */ -#line 147 "cmFortranParser.y" +#line 149 "cmFortranParser.y" { if (cmsysString_strcasecmp((yyvsp[-4].string), "non_intrinsic") == 0) { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); @@ -1728,139 +1750,139 @@ yyreduce: free((yyvsp[-4].string)); free((yyvsp[-2].string)); } -#line 1732 "cmFortranParser.cxx" +#line 1754 "cmFortranParser.cxx" break; case 13: /* stmt: INCLUDE STRING other EOSTMT */ -#line 155 "cmFortranParser.y" +#line 157 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1742 "cmFortranParser.cxx" +#line 1764 "cmFortranParser.cxx" break; case 14: /* stmt: CPP_LINE_DIRECTIVE STRING other EOSTMT */ -#line 160 "cmFortranParser.y" +#line 162 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1752 "cmFortranParser.cxx" +#line 1774 "cmFortranParser.cxx" break; case 15: /* stmt: CPP_INCLUDE_ANGLE other EOSTMT */ -#line 165 "cmFortranParser.y" +#line 167 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1762 "cmFortranParser.cxx" +#line 1784 "cmFortranParser.cxx" break; case 16: /* stmt: include STRING other EOSTMT */ -#line 170 "cmFortranParser.y" +#line 172 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1772 "cmFortranParser.cxx" +#line 1794 "cmFortranParser.cxx" break; case 17: /* stmt: define WORD other EOSTMT */ -#line 175 "cmFortranParser.y" +#line 177 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleDefine(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1782 "cmFortranParser.cxx" +#line 1804 "cmFortranParser.cxx" break; case 18: /* stmt: undef WORD other EOSTMT */ -#line 180 "cmFortranParser.y" +#line 182 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleUndef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1792 "cmFortranParser.cxx" +#line 1814 "cmFortranParser.cxx" break; case 19: /* stmt: ifdef WORD other EOSTMT */ -#line 185 "cmFortranParser.y" +#line 187 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1802 "cmFortranParser.cxx" +#line 1824 "cmFortranParser.cxx" break; case 20: /* stmt: ifndef WORD other EOSTMT */ -#line 190 "cmFortranParser.y" +#line 192 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1812 "cmFortranParser.cxx" +#line 1834 "cmFortranParser.cxx" break; case 21: /* stmt: if other EOSTMT */ -#line 195 "cmFortranParser.y" +#line 197 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIf(parser); } -#line 1821 "cmFortranParser.cxx" +#line 1843 "cmFortranParser.cxx" break; case 22: /* stmt: elif other EOSTMT */ -#line 199 "cmFortranParser.y" +#line 201 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleElif(parser); } -#line 1830 "cmFortranParser.cxx" +#line 1852 "cmFortranParser.cxx" break; case 23: /* stmt: else other EOSTMT */ -#line 203 "cmFortranParser.y" +#line 205 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleElse(parser); } -#line 1839 "cmFortranParser.cxx" +#line 1861 "cmFortranParser.cxx" break; case 24: /* stmt: endif other EOSTMT */ -#line 207 "cmFortranParser.y" +#line 209 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleEndif(parser); } -#line 1848 "cmFortranParser.cxx" +#line 1870 "cmFortranParser.cxx" break; case 48: /* misc_code: WORD */ -#line 229 "cmFortranParser.y" +#line 231 "cmFortranParser.y" { free ((yyvsp[0].string)); } -#line 1854 "cmFortranParser.cxx" +#line 1876 "cmFortranParser.cxx" break; case 55: /* misc_code: STRING */ -#line 236 "cmFortranParser.y" +#line 238 "cmFortranParser.y" { free ((yyvsp[0].string)); } -#line 1860 "cmFortranParser.cxx" +#line 1882 "cmFortranParser.cxx" break; -#line 1864 "cmFortranParser.cxx" +#line 1886 "cmFortranParser.cxx" default: break; } @@ -2085,6 +2107,6 @@ yyreturn: return yyresult; } -#line 248 "cmFortranParser.y" +#line 250 "cmFortranParser.y" /* End of grammar */ diff --git a/Source/LexerParser/cmFortranParser.y b/Source/LexerParser/cmFortranParser.y index e461160..a3e1c24 100644 --- a/Source/LexerParser/cmFortranParser.y +++ b/Source/LexerParser/cmFortranParser.y @@ -92,6 +92,8 @@ static void cmFortran_yyerror(yyscan_t yyscanner, const char* message) %token SUBMODULE %token USE +%destructor { free($$); } WORD STRING CPP_INCLUDE_ANGLE + /*-------------------------------------------------------------------------*/ /* grammar */ %% diff --git a/Source/cmCMakePresetsFileReadJSON.cxx b/Source/cmCMakePresetsFileReadJSON.cxx index 909a78b..489551d 100644 --- a/Source/cmCMakePresetsFileReadJSON.cxx +++ b/Source/cmCMakePresetsFileReadJSON.cxx @@ -350,8 +350,8 @@ auto const PresetVectorStringHelper = ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetStringHelper); -ReadFileResult PresetInheritsHelper(std::vector<std::string>& out, - const Json::Value* value) +ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out, + const Json::Value* value) { out.clear(); if (!value) { @@ -478,8 +478,8 @@ auto const ConfigurePresetHelper = cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) .Bind("name"_s, &ConfigurePreset::Name, PresetStringHelper) - .Bind("inherits"_s, &ConfigurePreset::Inherits, PresetInheritsHelper, - false) + .Bind("inherits"_s, &ConfigurePreset::Inherits, + PresetVectorOneOrMoreStringHelper, false) .Bind("hidden"_s, &ConfigurePreset::Hidden, PresetBoolHelper, false) .Bind<std::nullptr_t>("vendor"_s, nullptr, VendorHelper(ReadFileResult::INVALID_PRESET), false) @@ -512,7 +512,8 @@ auto const BuildPresetHelper = cmJSONObjectHelper<BuildPreset, ReadFileResult>( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) .Bind("name"_s, &BuildPreset::Name, PresetStringHelper) - .Bind("inherits"_s, &BuildPreset::Inherits, PresetInheritsHelper, false) + .Bind("inherits"_s, &BuildPreset::Inherits, + PresetVectorOneOrMoreStringHelper, false) .Bind("hidden"_s, &BuildPreset::Hidden, PresetBoolHelper, false) .Bind<std::nullptr_t>("vendor"_s, nullptr, VendorHelper(ReadFileResult::INVALID_PRESET), false) @@ -528,7 +529,8 @@ auto const BuildPresetHelper = &BuildPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper, false) .Bind("jobs"_s, &BuildPreset::Jobs, PresetOptionalIntHelper, false) - .Bind("targets"_s, &BuildPreset::Targets, PresetVectorStringHelper, false) + .Bind("targets"_s, &BuildPreset::Targets, + PresetVectorOneOrMoreStringHelper, false) .Bind("configuration"_s, &BuildPreset::Configuration, PresetStringHelper, false) .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, PresetOptionalBoolHelper, @@ -831,7 +833,8 @@ auto const TestPresetHelper = cmJSONObjectHelper<TestPreset, ReadFileResult>( ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) .Bind("name"_s, &TestPreset::Name, PresetStringHelper) - .Bind("inherits"_s, &TestPreset::Inherits, PresetInheritsHelper, false) + .Bind("inherits"_s, &TestPreset::Inherits, + PresetVectorOneOrMoreStringHelper, false) .Bind("hidden"_s, &TestPreset::Hidden, PresetBoolHelper, false) .Bind<std::nullptr_t>("vendor"_s, nullptr, VendorHelper(ReadFileResult::INVALID_PRESET), false) diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 7534e37..7c469c8 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -1612,8 +1612,33 @@ int cmCTest::GenerateDoneFile() return 0; } +bool cmCTest::TryToChangeDirectory(std::string const& dir) +{ + cmCTestLog(this, OUTPUT, + "Internal ctest changing into directory: " << dir << std::endl); + cmsys::Status status = cmSystemTools::ChangeDirectory(dir); + if (!status) { + auto msg = "Failed to change working directory to \"" + dir + + "\" : " + status.GetString() + "\n"; + cmCTestLog(this, ERROR_MESSAGE, msg); + return false; + } + return true; +} + std::string cmCTest::Base64GzipEncodeFile(std::string const& file) { + const std::string currDir = cmSystemTools::GetCurrentWorkingDirectory(); + std::string parentDir = cmSystemTools::GetParentDirectory(file); + + // Temporarily change to the file's directory so the tar gets created + // with a flat directory structure. + if (currDir != parentDir) { + if (!this->TryToChangeDirectory(parentDir)) { + return ""; + } + } + std::string tarFile = file + "_temp.tar.gz"; std::vector<std::string> files; files.push_back(file); @@ -1628,6 +1653,12 @@ std::string cmCTest::Base64GzipEncodeFile(std::string const& file) } std::string base64 = this->Base64EncodeFile(tarFile); cmSystemTools::RemoveFile(tarFile); + + // Change back to the directory we started in. + if (currDir != parentDir) { + cmSystemTools::ChangeDirectory(currDir); + } + return base64; } @@ -2853,14 +2884,7 @@ int cmCTest::ExecuteTests() } if (currDir != workDir) { - cmCTestLog(this, OUTPUT, - "Internal ctest changing into directory: " << workDir - << std::endl); - cmsys::Status status = cmSystemTools::ChangeDirectory(workDir); - if (!status) { - auto msg = "Failed to change working directory to \"" + workDir + - "\" : " + status.GetString() + "\n"; - cmCTestLog(this, ERROR_MESSAGE, msg); + if (!this->TryToChangeDirectory(workDir)) { return 1; } } diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 392eb1c..551c116 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -536,6 +536,9 @@ private: int RunCMakeAndTest(std::string* output); int ExecuteTests(); + /** return true iff change directory was successful */ + bool TryToChangeDirectory(std::string const& dir); + struct Private; std::unique_ptr<Private> Impl; }; diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 4a6518fd..0b27e34 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -7,6 +7,7 @@ #include <cstdio> #include <iterator> #include <sstream> +#include <unordered_map> #include <utility> #include <cm/memory> @@ -371,6 +372,12 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry qe) // This target provides its own link interface information. this->AddLinkEntries(depender_index, iface->Libraries); this->AddLinkObjects(iface->Objects); + for (auto const& language : iface->Languages) { + auto runtimeEntries = iface->LanguageRuntimeLibraries.find(language); + if (runtimeEntries != iface->LanguageRuntimeLibraries.end()) { + this->AddLinkEntries(depender_index, runtimeEntries->second); + } + } if (isIface) { return; @@ -516,6 +523,13 @@ void cmComputeLinkDepends::AddDirectLinkEntries() this->Target->GetLinkImplementation(this->Config); this->AddLinkEntries(-1, impl->Libraries); this->AddLinkObjects(impl->Objects); + + for (auto const& language : impl->Languages) { + auto runtimeEntries = impl->LanguageRuntimeLibraries.find(language); + if (runtimeEntries != impl->LanguageRuntimeLibraries.end()) { + this->AddLinkEntries(-1, runtimeEntries->second); + } + } for (cmLinkItem const& wi : impl->WrongConfigLibraries) { this->CheckWrongConfigItem(wi); } diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 2647998..d15da0c 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -585,10 +585,10 @@ void cmComputeLinkInformation::AddImplicitLinkInfo() this->Target->GetLinkClosure(this->Config); for (std::string const& li : lc->Languages) { - if (li == "CUDA") { + if (li == "CUDA" || li == "HIP") { // These need to go before the other implicit link information // as they could require symbols from those other library - // Currently restricted to CUDA as it is the only language + // Currently restricted as CUDA and HIP are the only languages // we have documented runtime behavior controls for this->AddRuntimeLinkLibrary(li); } diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 5399fd0..8ecf264 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -189,6 +189,8 @@ SETUP_LANGUAGE(cuda_properties, CUDA); // NOLINTNEXTLINE(bugprone-suspicious-missing-comma) SETUP_LANGUAGE(fortran_properties, Fortran); // NOLINTNEXTLINE(bugprone-suspicious-missing-comma) +SETUP_LANGUAGE(hip_properties, HIP); +// NOLINTNEXTLINE(bugprone-suspicious-missing-comma) SETUP_LANGUAGE(objc_properties, OBJC); // NOLINTNEXTLINE(bugprone-suspicious-missing-comma) SETUP_LANGUAGE(objcxx_properties, OBJCXX); @@ -201,6 +203,8 @@ SETUP_LANGUAGE(swift_properties, Swift); 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_HIP_ARCHITECTURES = "CMAKE_HIP_ARCHITECTURES"; +std::string const kCMAKE_HIP_RUNTIME_LIBRARY = "CMAKE_HIP_RUNTIME_LIBRARY"; std::string const kCMAKE_ISPC_INSTRUCTION_SETS = "CMAKE_ISPC_INSTRUCTION_SETS"; std::string const kCMAKE_ISPC_HEADER_SUFFIX = "CMAKE_ISPC_HEADER_SUFFIX"; std::string const kCMAKE_LINK_SEARCH_END_STATIC = @@ -274,6 +278,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, LanguageStandardState cState("C"); LanguageStandardState cudaState("CUDA"); LanguageStandardState cxxState("CXX"); + LanguageStandardState hipState("HIP"); LanguageStandardState objcState("OBJC"); LanguageStandardState objcxxState("OBJCXX"); std::vector<std::string> targets; @@ -323,6 +328,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } else if (cState.UpdateIfMatches(argv, i) || cxxState.UpdateIfMatches(argv, i) || cudaState.UpdateIfMatches(argv, i) || + hipState.UpdateIfMatches(argv, i) || objcState.UpdateIfMatches(argv, i) || objcxxState.UpdateIfMatches(argv, i)) { continue; @@ -428,6 +434,9 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, if (!cudaState.Validate(this->Makefile)) { return -1; } + if (!hipState.Validate(this->Makefile)) { + return -1; + } if (!cxxState.Validate(this->Makefile)) { return -1; } @@ -715,6 +724,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, vars.insert( &fortran_properties[lang_property_start], &fortran_properties[lang_property_start + lang_property_size]); + vars.insert(&hip_properties[lang_property_start], + &hip_properties[lang_property_start + lang_property_size]); vars.insert(&objc_properties[lang_property_start], &objc_properties[lang_property_start + lang_property_size]); vars.insert( @@ -727,6 +738,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, vars.insert(kCMAKE_CUDA_ARCHITECTURES); vars.insert(kCMAKE_CUDA_RUNTIME_LIBRARY); vars.insert(kCMAKE_ENABLE_EXPORTS); + vars.insert(kCMAKE_HIP_ARCHITECTURES); + vars.insert(kCMAKE_HIP_RUNTIME_LIBRARY); vars.insert(kCMAKE_ISPC_INSTRUCTION_SETS); vars.insert(kCMAKE_ISPC_HEADER_SUFFIX); vars.insert(kCMAKE_LINK_SEARCH_END_STATIC); @@ -761,6 +774,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, vars.insert( &fortran_properties[pie_property_start], &fortran_properties[pie_property_start + pie_property_size]); + vars.insert(&hip_properties[pie_property_start], + &hip_properties[pie_property_start + pie_property_size]); vars.insert(&objc_properties[pie_property_start], &objc_properties[pie_property_start + pie_property_size]); vars.insert( @@ -835,6 +850,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, cState.Enabled(testLangs.find("C") != testLangs.end()); cxxState.Enabled(testLangs.find("CXX") != testLangs.end()); cudaState.Enabled(testLangs.find("CUDA") != testLangs.end()); + hipState.Enabled(testLangs.find("HIP") != testLangs.end()); objcState.Enabled(testLangs.find("OBJC") != testLangs.end()); objcxxState.Enabled(testLangs.find("OBJCXX") != testLangs.end()); @@ -842,7 +858,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, bool honorStandard = true; if (cState.DidNone() && cxxState.DidNone() && objcState.DidNone() && - objcxxState.DidNone() && cudaState.DidNone()) { + objcxxState.DidNone() && cudaState.DidNone() && hipState.DidNone()) { switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0067)) { case cmPolicies::WARN: warnCMP0067 = this->Makefile->PolicyOptionalWarningEnabled( @@ -872,6 +888,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, warnCMP0067, warnCMP0067Variables); cudaState.LoadUnsetPropertyValues(this->Makefile, honorStandard, warnCMP0067, warnCMP0067Variables); + hipState.LoadUnsetPropertyValues(this->Makefile, honorStandard, + warnCMP0067, warnCMP0067Variables); objcState.LoadUnsetPropertyValues(this->Makefile, honorStandard, warnCMP0067, warnCMP0067Variables); objcxxState.LoadUnsetPropertyValues(this->Makefile, honorStandard, @@ -894,6 +912,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, cState.WriteProperties(fout, targetName); cxxState.WriteProperties(fout, targetName); cudaState.WriteProperties(fout, targetName); + hipState.WriteProperties(fout, targetName); objcState.WriteProperties(fout, targetName); objcxxState.WriteProperties(fout, targetName); diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index f217201..df14261 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -366,10 +366,11 @@ void cmExtraCodeBlocksGenerator::CreateNewProjectFile( continue; } - // check whether it is a C/C++/CUDA implementation file + // check whether it is a C/C++/CUDA/HIP implementation file bool isCFile = false; std::string lang = s->GetOrDetermineLanguage(); - if (lang == "C" || lang == "CXX" || lang == "CUDA") { + if (lang == "C" || lang == "CXX" || lang == "CUDA" || + lang == "HIP") { std::string const& srcext = s->GetExtension(); isCFile = cm->IsACLikeSourceExtension(srcext); } diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 8030b64..c608bf9 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -718,7 +718,7 @@ struct CompilerIdNode : public cmGeneratorExpressionNode static const CompilerIdNode cCompilerIdNode("C"), cxxCompilerIdNode("CXX"), cudaCompilerIdNode("CUDA"), objcCompilerIdNode("OBJC"), objcxxCompilerIdNode("OBJCXX"), fortranCompilerIdNode("Fortran"), - ispcCompilerIdNode("ISPC"); + hipCompilerIdNode("HIP"), ispcCompilerIdNode("ISPC"); struct CompilerVersionNode : public cmGeneratorExpressionNode { @@ -783,7 +783,8 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode static const CompilerVersionNode cCompilerVersionNode("C"), cxxCompilerVersionNode("CXX"), cudaCompilerVersionNode("CUDA"), objcCompilerVersionNode("OBJC"), objcxxCompilerVersionNode("OBJCXX"), - fortranCompilerVersionNode("Fortran"), ispcCompilerVersionNode("ISPC"); + fortranCompilerVersionNode("Fortran"), ispcCompilerVersionNode("ISPC"), + hipCompilerVersionNode("HIP"); struct PlatformIdNode : public cmGeneratorExpressionNode { @@ -2597,6 +2598,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "OBJCXX_COMPILER_ID", &objcxxCompilerIdNode }, { "CUDA_COMPILER_ID", &cudaCompilerIdNode }, { "Fortran_COMPILER_ID", &fortranCompilerIdNode }, + { "HIP_COMPILER_ID", &hipCompilerIdNode }, { "VERSION_GREATER", &versionGreaterNode }, { "VERSION_GREATER_EQUAL", &versionGreaterEqNode }, { "VERSION_LESS", &versionLessNode }, @@ -2608,6 +2610,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "OBJC_COMPILER_VERSION", &objcCompilerVersionNode }, { "OBJCXX_COMPILER_VERSION", &objcxxCompilerVersionNode }, { "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode }, + { "HIP_COMPILER_VERSION", &hipCompilerVersionNode }, { "PLATFORM_ID", &platformIdNode }, { "COMPILE_FEATURES", &compileFeaturesNode }, { "CONFIGURATION", &configurationNode }, diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 5deb2df..f268c6c 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -697,6 +697,7 @@ void cmGeneratorTarget::ClearSourcesCache() this->SourcesAreContextDependent = Tribool::Indeterminate; this->Objects.clear(); this->VisitedConfigsForObjects.clear(); + this->LinkImplMap.clear(); } void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before) @@ -979,7 +980,7 @@ cmProp cmGeneratorTarget::GetPropertyWithPairedLanguageSupport( // 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") { + } else if (lang == "OBJCXX" || lang == "CUDA" || lang == "HIP") { propertyValue = this->GetPropertyWithPairedLanguageSupport("CXX", suffix); } @@ -1120,7 +1121,7 @@ void cmGeneratorTarget::AppendLanguageSideEffects( std::map<std::string, std::set<cmGeneratorTarget const*>>& sideEffects) const { static const std::set<cm::string_view> LANGS_WITH_NO_SIDE_EFFECTS = { - "C"_s, "CXX"_s, "OBJC"_s, "OBJCXX"_s, "ASM"_s, "CUDA"_s, + "C"_s, "CXX"_s, "OBJC"_s, "OBJCXX"_s, "ASM"_s, "CUDA"_s, "HIP"_s }; for (auto const& lang : this->GetAllConfigCompileLanguages()) { @@ -1234,6 +1235,20 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory( &dagChecker, result, excludeImported, language); } + cmLinkImplementation const* impl = this->GetLinkImplementation(config); + if (impl != nullptr) { + auto runtimeEntries = impl->LanguageRuntimeLibraries.find(language); + if (runtimeEntries != impl->LanguageRuntimeLibraries.end()) { + for (auto const& lib : runtimeEntries->second) { + if (lib.Target) { + handleSystemIncludesDep(this->LocalGenerator, lib.Target, config, + this, &dagChecker, result, excludeImported, + language); + } + } + } + } + std::for_each(result.begin(), result.end(), cmSystemTools::ConvertToUnixSlashes); std::sort(result.begin(), result.end()); @@ -1473,31 +1488,80 @@ void AddLangSpecificImplicitIncludeDirectories( } } +void addInterfaceEntry(cmGeneratorTarget const* headTarget, + std::string const& config, std::string const& prop, + std::string const& lang, + cmGeneratorExpressionDAGChecker* dagChecker, + EvaluatedTargetPropertyEntries& entries, + bool usage_requirements_only, + std::vector<cmLinkImplItem> const& libraries) +{ + for (cmLinkImplItem const& lib : libraries) { + if (lib.Target) { + EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace); + // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our + // caller's property and hand-evaluate it as if it were compiled. + // Create a context as cmCompiledGeneratorExpression::Evaluate does. + cmGeneratorExpressionContext context( + headTarget->GetLocalGenerator(), config, false, headTarget, headTarget, + true, lib.Backtrace, lang); + cmExpandList(lib.Target->EvaluateInterfaceProperty( + prop, &context, dagChecker, usage_requirements_only), + ee.Values); + ee.ContextDependent = context.HadContextSensitiveCondition; + entries.Entries.emplace_back(std::move(ee)); + } + } +} + +// IncludeRuntimeInterface is used to break the cycle in computing +// the necessary transitive dependencies of targets that can occur +// now that we have implicit language runtime targets. +// +// To determine the set of languages that a target has we need to iterate +// all the sources which includes transitive INTERFACE sources. +// Therefore we can't determine what language runtimes are needed +// for a target until after all sources are computed. +// +// Therefore while computing the applicable INTERFACE_SOURCES we +// must ignore anything in LanguageRuntimeLibraries or we would +// create a cycle ( INTERFACE_SOURCES requires LanguageRuntimeLibraries, +// LanguageRuntimeLibraries requires INTERFACE_SOURCES). +// +enum class IncludeRuntimeInterface +{ + Yes, + No +}; void AddInterfaceEntries(cmGeneratorTarget const* headTarget, std::string const& config, std::string const& prop, std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, EvaluatedTargetPropertyEntries& entries, + IncludeRuntimeInterface searchRuntime, bool usage_requirements_only = true) { - if (cmLinkImplementationLibraries const* impl = - headTarget->GetLinkImplementationLibraries(config)) { - entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; - for (cmLinkImplItem const& lib : impl->Libraries) { - if (lib.Target) { - EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace); - // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our - // caller's property and hand-evaluate it as if it were compiled. - // Create a context as cmCompiledGeneratorExpression::Evaluate does. - cmGeneratorExpressionContext context( - headTarget->GetLocalGenerator(), config, false, headTarget, - headTarget, true, lib.Backtrace, lang); - cmExpandList(lib.Target->EvaluateInterfaceProperty( - prop, &context, dagChecker, usage_requirements_only), - ee.Values); - ee.ContextDependent = context.HadContextSensitiveCondition; - entries.Entries.emplace_back(std::move(ee)); + if (searchRuntime == IncludeRuntimeInterface::Yes) { + if (cmLinkImplementation const* impl = + headTarget->GetLinkImplementation(config)) { + entries.HadContextSensitiveCondition = + impl->HadContextSensitiveCondition; + + auto runtimeLibIt = impl->LanguageRuntimeLibraries.find(lang); + if (runtimeLibIt != impl->LanguageRuntimeLibraries.end()) { + addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries, + usage_requirements_only, runtimeLibIt->second); } + addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries, + usage_requirements_only, impl->Libraries); + } + } else { + if (cmLinkImplementationLibraries const* impl = + headTarget->GetLinkImplementationLibraries(config)) { + entries.HadContextSensitiveCondition = + impl->HadContextSensitiveCondition; + addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries, + usage_requirements_only, impl->Libraries); } } } @@ -1655,7 +1719,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( // Collect INTERFACE_SOURCES of all direct link-dependencies. EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries; AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(), - &dagChecker, linkInterfaceSourcesEntries); + &dagChecker, linkInterfaceSourcesEntries, + IncludeRuntimeInterface::No, true); std::vector<std::string>::size_type numFilesBefore = files.size(); bool contextDependentInterfaceSources = processSources( this, linkInterfaceSourcesEntries, files, uniqueSrcs, debugSources); @@ -3350,6 +3415,29 @@ void cmGeneratorTarget::AddISPCTargetFlags(std::string& flags) const } } +void cmGeneratorTarget::AddHIPArchitectureFlags(std::string& flags) const +{ + const std::string& property = this->GetSafeProperty("HIP_ARCHITECTURES"); + + if (property.empty()) { + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, + "HIP_ARCHITECTURES is empty for target \"" + + this->GetName() + "\"."); + } + + // If HIP_ARCHITECTURES is false we don't add any architectures. + if (cmIsOff(property)) { + return; + } + + std::vector<std::string> options; + cmExpandList(property, options); + + for (std::string& option : options) { + flags += " --offload-arch=" + option; + } +} + void cmGeneratorTarget::AddCUDAToolkitFlags(std::string& flags) const { std::string const& compiler = @@ -3569,7 +3657,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( } AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang, - &dagChecker, entries); + &dagChecker, entries, IncludeRuntimeInterface::Yes); if (this->Makefile->IsOn("APPLE")) { if (cmLinkImplementationLibraries const* impl = @@ -3794,7 +3882,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions( this, config, language, &dagChecker, this->CompileOptionsEntries); AddInterfaceEntries(this, config, "INTERFACE_COMPILE_OPTIONS", language, - &dagChecker, entries); + &dagChecker, entries, IncludeRuntimeInterface::Yes); processOptions(this, entries, result, uniqueOptions, debugOptions, "compile options", OptionsParse::Shell); @@ -3836,7 +3924,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures( this, config, std::string(), &dagChecker, this->CompileFeaturesEntries); AddInterfaceEntries(this, config, "INTERFACE_COMPILE_FEATURES", - std::string(), &dagChecker, entries); + std::string(), &dagChecker, entries, + IncludeRuntimeInterface::Yes); processOptions(this, entries, result, uniqueFeatures, debugFeatures, "compile features", OptionsParse::None); @@ -3880,7 +3969,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( this, config, language, &dagChecker, this->CompileDefinitionsEntries); AddInterfaceEntries(this, config, "INTERFACE_COMPILE_DEFINITIONS", language, - &dagChecker, entries); + &dagChecker, entries, IncludeRuntimeInterface::Yes); if (!config.empty()) { std::string configPropName = @@ -3938,7 +4027,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( this, config, language, &dagChecker, this->PrecompileHeadersEntries); AddInterfaceEntries(this, config, "INTERFACE_PRECOMPILE_HEADERS", language, - &dagChecker, entries); + &dagChecker, entries, IncludeRuntimeInterface::Yes); std::vector<BT<std::string>> list; processOptions(this, entries, list, uniqueOptions, debugDefines, @@ -4323,7 +4412,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( this, config, language, &dagChecker, this->LinkOptionsEntries); AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language, - &dagChecker, entries, + &dagChecker, entries, IncludeRuntimeInterface::Yes, this->GetPolicyStatusCMP0099() != cmPolicies::NEW); processOptions(this, entries, result, uniqueOptions, debugOptions, @@ -4582,7 +4671,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( this, config, language, &dagChecker, this->LinkDirectoriesEntries); AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language, - &dagChecker, entries, + &dagChecker, entries, IncludeRuntimeInterface::Yes, this->GetPolicyStatusCMP0099() != cmPolicies::NEW); processLinkDirectories(this, entries, result, uniqueDirectories, @@ -4621,7 +4710,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( } } AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language, - &dagChecker, entries, + &dagChecker, entries, IncludeRuntimeInterface::Yes, this->GetPolicyStatusCMP0099() != cmPolicies::NEW); processOptions(this, entries, result, uniqueOptions, false, "link depends", @@ -4741,7 +4830,8 @@ bool cmGeneratorTarget::ComputeCompileFeatures( } // Custom updates for the CUDA standard. - if (generatorTargetLanguageStandard && language.first == "CUDA") { + if (generatorTargetLanguageStandard != nullptr && + (language.first == "CUDA")) { if (generatorTargetLanguageStandard->Value == "98") { this->LanguageStandardMap[key].Value = "03"; } @@ -6363,6 +6453,7 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( iface.AllDone = true; if (iface.Exists) { this->ComputeLinkInterface(config, iface, head, secondPass); + this->ComputeLinkInterfaceRuntimeLibraries(config, iface); } } @@ -6886,6 +6977,83 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( } } +namespace { + +template <typename ReturnType> +ReturnType constructItem(cmGeneratorTarget* target, + cmListFileBacktrace const& bt); + +template <> +inline cmLinkImplItem constructItem(cmGeneratorTarget* target, + cmListFileBacktrace const& bt) +{ + return cmLinkImplItem(cmLinkItem(target, false, bt), false); +} + +template <> +inline cmLinkItem constructItem(cmGeneratorTarget* target, + cmListFileBacktrace const& bt) +{ + return cmLinkItem(target, false, bt); +} + +template <typename ValueType> +std::vector<ValueType> computeImplicitLanguageTargets( + std::string const& lang, std::string const& config, + cmGeneratorTarget const* currentTarget) +{ + cmListFileBacktrace bt; + std::vector<ValueType> result; + cmLocalGenerator* lg = currentTarget->GetLocalGenerator(); + + std::string const& runtimeLibrary = + currentTarget->GetRuntimeLinkLibrary(lang, config); + if (cmProp runtimeLinkOptions = currentTarget->Makefile->GetDefinition( + "CMAKE_" + lang + "_RUNTIME_LIBRARIES_" + runtimeLibrary)) { + std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions); + result.reserve(libsVec.size()); + + for (std::string const& i : libsVec) { + cmGeneratorTarget::TargetOrString resolved = + currentTarget->ResolveTargetReference(i, lg); + if (resolved.Target) { + result.emplace_back(constructItem<ValueType>(resolved.Target, bt)); + } + } + } + + return result; +} +} + +void cmGeneratorTarget::ComputeLinkInterfaceRuntimeLibraries( + const std::string& config, cmOptionalLinkInterface& iface) const +{ + for (std::string const& lang : iface.Languages) { + if ((lang == "CUDA" || lang == "HIP") && + iface.LanguageRuntimeLibraries.find(lang) == + iface.LanguageRuntimeLibraries.end()) { + auto implicitTargets = + computeImplicitLanguageTargets<cmLinkItem>(lang, config, this); + iface.LanguageRuntimeLibraries[lang] = std::move(implicitTargets); + } + } +} + +void cmGeneratorTarget::ComputeLinkImplementationRuntimeLibraries( + const std::string& config, cmOptionalLinkImplementation& impl) const +{ + for (std::string const& lang : impl.Languages) { + if ((lang == "CUDA" || lang == "HIP") && + impl.LanguageRuntimeLibraries.find(lang) == + impl.LanguageRuntimeLibraries.end()) { + auto implicitTargets = + computeImplicitLanguageTargets<cmLinkImplItem>(lang, config, this); + impl.LanguageRuntimeLibraries[lang] = std::move(implicitTargets); + } + } +} + const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( const std::string& config, cmGeneratorTarget const* headTarget, bool usage_requirements_only, bool secondPass) const @@ -7150,6 +7318,7 @@ const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( if (!impl.LanguagesDone) { impl.LanguagesDone = true; this->ComputeLinkImplementationLanguages(config, impl); + this->ComputeLinkImplementationRuntimeLibraries(config, impl); } return &impl; } diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index be36f3f..ed66fb1 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -459,6 +459,8 @@ public: void AddCUDAArchitectureFlags(std::string& flags) const; void AddCUDAToolkitFlags(std::string& flags) const; + void AddHIPArchitectureFlags(std::string& flags) const; + void AddISPCTargetFlags(std::string& flags) const; std::string GetFeatureSpecificLinkRuleVariable( @@ -1109,6 +1111,12 @@ private: cmProp GetPropertyWithPairedLanguageSupport(std::string const& lang, const char* suffix) const; + void ComputeLinkImplementationRuntimeLibraries( + const std::string& config, cmOptionalLinkImplementation& impl) const; + + void ComputeLinkInterfaceRuntimeLibraries( + const std::string& config, cmOptionalLinkInterface& iface) const; + public: const std::vector<const cmGeneratorTarget*>& GetLinkImplementationClosure( const std::string& config) const; diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h index db44938..0863edd 100644 --- a/Source/cmLinkItem.h +++ b/Source/cmLinkItem.h @@ -7,6 +7,7 @@ #include <map> #include <ostream> #include <string> +#include <unordered_map> #include <vector> #include <cmext/algorithm> @@ -80,6 +81,8 @@ struct cmLinkInterface : public cmLinkInterfaceLibraries { // Languages whose runtime libraries must be linked. std::vector<std::string> Languages; + std::unordered_map<std::string, std::vector<cmLinkItem>> + LanguageRuntimeLibraries; // Shared library dependencies needed for linking on some platforms. std::vector<cmLinkItem> SharedDeps; @@ -115,6 +118,8 @@ struct cmLinkImplementation : public cmLinkImplementationLibraries { // Languages whose runtime libraries must be linked. std::vector<std::string> Languages; + std::unordered_map<std::string, std::vector<cmLinkImplItem>> + LanguageRuntimeLibraries; // Whether the list depends on a link language genex. bool HadLinkLanguageSensitiveCondition = false; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 6a49b84..3b282de 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -780,9 +780,9 @@ bool cmLocalGenerator::ComputeTargetCompileFeatures() this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); using LanguagePair = std::pair<std::string, std::string>; - std::vector<LanguagePair> pairedLanguages{ { "OBJC", "C" }, - { "OBJCXX", "CXX" }, - { "CUDA", "CXX" } }; + std::vector<LanguagePair> pairedLanguages{ + { "OBJC", "C" }, { "OBJCXX", "CXX" }, { "CUDA", "CXX" }, { "HIP", "CXX" } + }; std::set<LanguagePair> inferredEnabledLanguages; for (auto const& lang : pairedLanguages) { if (this->Makefile->GetState()->GetLanguageEnabled(lang.first)) { @@ -1404,8 +1404,8 @@ void cmLocalGenerator::GetDeviceLinkFlags( linkLineComputer->GetLinkerLanguage(target, config); if (pcli) { - // Compute the required cuda device link libraries when - // resolving cuda device symbols + // Compute the required device link libraries when + // resolving gpu lang device symbols this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, frameworkPath, linkPath); } @@ -1968,6 +1968,8 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags, compilerSimulateId = this->Makefile->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID"); } + } else if (lang == "HIP") { + target->AddHIPArchitectureFlags(flags); } // Add VFS Overlay for Clang compilers diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 3a65a80..0667c55 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -289,9 +289,9 @@ void cmLocalUnixMakefileGenerator3::WriteLocalMakefile() for (LocalObjectEntry const& entry : localObjectFile.second) { if (entry.Language == "C" || entry.Language == "CXX" || entry.Language == "CUDA" || entry.Language == "Fortran" || - entry.Language == "ISPC") { - // Right now, C, C++, Fortran and CUDA have both a preprocessor and the - // ability to generate assembly code + entry.Language == "HIP" || entry.Language == "ISPC") { + // Right now, C, C++, CUDA, Fortran, HIP and ISPC have both a + // preprocessor and the ability to generate assembly code lang_has_preprocessor = true; lang_has_assembly = true; break; @@ -1550,7 +1550,7 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies( std::unique_ptr<cmDepends> scanner; if (lang == "C" || lang == "CXX" || lang == "RC" || lang == "ASM" || lang == "OBJC" || lang == "OBJCXX" || lang == "CUDA" || - lang == "ISPC") { + lang == "HIP" || lang == "ISPC") { // TODO: Handle RC (resource files) dependencies correctly. scanner = cm::make_unique<cmDependsC>(this, targetDir, lang, &validDeps); } diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index e87f81b..6d8376c 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -945,7 +945,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string compilerLauncher; if (!compileCommands.empty() && (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" || - lang == "ISPC" || lang == "OBJC" || lang == "OBJCXX")) { + lang == "HIP" || lang == "ISPC" || lang == "OBJC" || + lang == "OBJCXX")) { std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); if (cmNonempty(clauncher)) { diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 4feb0bb..6080270 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -833,7 +833,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, std::string compilerLauncher; if (!compileCmds.empty() && (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA" || - lang == "ISPC" || lang == "OBJC" || lang == "OBJCXX")) { + lang == "HIP" || lang == "ISPC" || lang == "OBJC" || + lang == "OBJCXX")) { std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER"); cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); if (cmNonempty(clauncher)) { diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx index b198a00..73d0fed 100644 --- a/Source/cmStandardLevelResolver.cxx +++ b/Source/cmStandardLevelResolver.cxx @@ -36,6 +36,9 @@ const char* const CXX_FEATURES[] = { nullptr FOR_EACH_CXX_FEATURE( const char* const CUDA_FEATURES[] = { nullptr FOR_EACH_CUDA_FEATURE( FEATURE_STRING) }; + +const char* const HIP_FEATURES[] = { nullptr FOR_EACH_HIP_FEATURE( + FEATURE_STRING) }; #undef FEATURE_STRING struct StandardNeeded @@ -306,8 +309,7 @@ struct StanardLevelComputer }; std::unordered_map<std::string, StanardLevelComputer> StandardComputerMapping = - { - { "C", + { { "C", StanardLevelComputer{ "C", std::vector<int>{ 90, 99, 11, 17, 23 }, std::vector<std::string>{ "90", "99", "11", "17", "23" } } }, @@ -326,7 +328,10 @@ std::unordered_map<std::string, StanardLevelComputer> StandardComputerMapping = StanardLevelComputer{ "OBJCXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 }, std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } }, - }; + { "HIP", + StanardLevelComputer{ + "HIP", std::vector<int>{ 98, 11, 14, 17, 20, 23 }, + std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } } }; } std::string cmStandardLevelResolver::GetCompileOptionDef( @@ -434,6 +439,13 @@ bool cmStandardLevelResolver::CompileFeatureKnown( lang = "CUDA"; return true; } + bool isHIPFeature = + std::find_if(cm::cbegin(HIP_FEATURES) + 1, cm::cend(HIP_FEATURES), + cmStrCmp(feature)) != cm::cend(HIP_FEATURES); + if (isHIPFeature) { + lang = "HIP"; + return true; + } std::ostringstream e; if (error) { e << "specified"; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 6f2e447..7622700 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -288,6 +288,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, SETUP_COMMON_LANGUAGE_PROPERTIES(CXX); SETUP_COMMON_LANGUAGE_PROPERTIES(OBJCXX); SETUP_COMMON_LANGUAGE_PROPERTIES(CUDA); + SETUP_COMMON_LANGUAGE_PROPERTIES(HIP); initProp("ANDROID_API"); initProp("ANDROID_API_MIN"); @@ -365,6 +366,8 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("CUDA_RESOLVE_DEVICE_SYMBOLS"); initProp("CUDA_RUNTIME_LIBRARY"); initProp("CUDA_ARCHITECTURES"); + initProp("HIP_RUNTIME_LIBRARY"); + initProp("HIP_ARCHITECTURES"); initProp("VISIBILITY_INLINES_HIDDEN"); initProp("JOB_POOL_COMPILE"); initProp("JOB_POOL_LINK"); @@ -1168,6 +1171,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) MAKE_STATIC_PROP(C_STANDARD); MAKE_STATIC_PROP(CXX_STANDARD); MAKE_STATIC_PROP(CUDA_STANDARD); + MAKE_STATIC_PROP(HIP_STANDARD); MAKE_STATIC_PROP(OBJC_STANDARD); MAKE_STATIC_PROP(OBJCXX_STANDARD); MAKE_STATIC_PROP(COMPILE_DEFINITIONS); @@ -1354,8 +1358,8 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) this->SetProperty("COMPILE_PDB_NAME", cmToCStr(tmp)); this->AddUtility(reusedFrom, false, this->impl->Makefile); } else if (prop == propC_STANDARD || prop == propCXX_STANDARD || - prop == propCUDA_STANDARD || prop == propOBJC_STANDARD || - prop == propOBJCXX_STANDARD) { + prop == propCUDA_STANDARD || prop == propHIP_STANDARD || + prop == propOBJC_STANDARD || prop == propOBJCXX_STANDARD) { if (value) { this->impl->LanguageStandardProperties[prop] = BTs<std::string>(value, this->impl->Makefile->GetBacktrace()); @@ -1461,8 +1465,8 @@ void cmTarget::AppendProperty(const std::string& prop, this->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") { + prop == "CUDA_STANDARD" || prop == "HIP_STANDARD" || + prop == "OBJC_STANDARD" || prop == "OBJCXX_STANDARD") { this->impl->Makefile->IssueMessage( MessageType::FATAL_ERROR, prop + " property may not be appended."); } else { diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 9a866ab..7868859 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -218,6 +218,7 @@ cmake::cmake(Role role, cmState::Mode mode) setupExts(this->CudaFileExtensions, { "cu" }); setupExts(this->FortranFileExtensions, { "f", "F", "for", "f77", "f90", "f95", "f03" }); + setupExts(this->HipFileExtensions, { "hip" }); setupExts(this->ISPCFileExtensions, { "ispc" }); } } @@ -2462,6 +2463,8 @@ std::vector<std::string> cmake::GetAllExtensions() const // cuda extensions are also in SourceFileExtensions so we ignore it here allExt.insert(allExt.end(), this->FortranFileExtensions.ordered.begin(), this->FortranFileExtensions.ordered.end()); + allExt.insert(allExt.end(), this->HipFileExtensions.ordered.begin(), + this->HipFileExtensions.ordered.end()); allExt.insert(allExt.end(), this->ISPCFileExtensions.ordered.begin(), this->ISPCFileExtensions.ordered.end()); return allExt; @@ -3273,7 +3276,9 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets, this->UnprocessedPresetEnvironment = expandedPreset->Environment; this->ProcessPresetEnvironment(); - if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL && expandedPreset->Jobs) { + if ((jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL || + jobs == cmake::NO_BUILD_PARALLEL_LEVEL) && + expandedPreset->Jobs) { jobs = *expandedPreset->Jobs; } diff --git a/Source/cmake.h b/Source/cmake.h index e845662..5a2a88f 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -297,7 +297,7 @@ public: return this->CLikeSourceFileExtensions.Test(ext) || this->CudaFileExtensions.Test(ext) || this->FortranFileExtensions.Test(ext) || - this->ISPCFileExtensions.Test(ext); + this->HipFileExtensions.Test(ext) || this->ISPCFileExtensions.Test(ext); } bool IsACLikeSourceExtension(cm::string_view ext) const @@ -662,6 +662,7 @@ private: FileExtensions CudaFileExtensions; FileExtensions ISPCFileExtensions; FileExtensions FortranFileExtensions; + FileExtensions HipFileExtensions; bool ClearBuildSystem = false; bool DebugTryCompile = false; bool RegenerateDuringBuild = false; @@ -838,3 +839,11 @@ private: F(cuda_std_17) \ F(cuda_std_20) \ F(cuda_std_23) + +#define FOR_EACH_HIP_FEATURE(F) \ + F(hip_std_98) \ + F(hip_std_11) \ + F(hip_std_14) \ + F(hip_std_17) \ + F(hip_std_20) \ + F(hip_std_23) |