diff --git a/Help/manual/cmake-instrumentation.7.rst b/Help/manual/cmake-instrumentation.7.rst index a0c43d3641..a54264677a 100644 --- a/Help/manual/cmake-instrumentation.7.rst +++ b/Help/manual/cmake-instrumentation.7.rst @@ -232,6 +232,10 @@ and contain the following data: The :prop_tgt:`TYPE` of the target. Only included when ``role`` is ``link``. + ``targetLabels`` + The :prop_tgt:`LABELS` of the target. Only included when ``role`` is + ``link``. + ``timeStart`` Time at which the command started, expressed as the number of milliseconds since the system epoch. @@ -296,8 +300,8 @@ Example: "beforeCPULoadAverage" : 2.3500000000000001, "beforeHostMemoryUsed" : 6635832.0 }, - "timeStart" : 31997009, - "timeStop" : 31997056 + "timeStart" : 1737053448177, + "duration" : 31 } v1 Index File diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx index 3a2db59cab..d8e14125c4 100644 --- a/Source/CTest/cmCTestLaunch.cxx +++ b/Source/CTest/cmCTestLaunch.cxx @@ -62,6 +62,7 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv) DoingOutput, DoingSource, DoingLanguage, + DoingTargetLabels, DoingTargetName, DoingTargetType, DoingCommandType, @@ -84,6 +85,8 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv) doing = DoingSource; } else if (strcmp(arg, "--language") == 0) { doing = DoingLanguage; + } else if (strcmp(arg, "--target-labels") == 0) { + doing = DoingTargetLabels; } else if (strcmp(arg, "--target-name") == 0) { doing = DoingTargetName; } else if (strcmp(arg, "--target-type") == 0) { @@ -106,6 +109,9 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv) this->Reporter.OptionLanguage = "C++"; } doing = DoingNone; + } else if (doing == DoingTargetLabels) { + this->Reporter.OptionTargetLabels = arg; + doing = DoingNone; } else if (doing == DoingTargetName) { this->Reporter.OptionTargetName = arg; doing = DoingNone; @@ -257,6 +263,7 @@ int cmCTestLaunch::Run() options["role"] = this->Reporter.OptionRole; std::map arrayOptions; arrayOptions["outputs"] = this->Reporter.OptionOutput; + arrayOptions["targetLabels"] = this->Reporter.OptionTargetLabels; instrumenter.InstrumentCommand( this->Reporter.OptionCommandType, this->RealArgV, [this]() -> int { diff --git a/Source/CTest/cmCTestLaunchReporter.h b/Source/CTest/cmCTestLaunchReporter.h index 16f14617c2..e5a2d5bb9b 100644 --- a/Source/CTest/cmCTestLaunchReporter.h +++ b/Source/CTest/cmCTestLaunchReporter.h @@ -34,6 +34,7 @@ public: std::string OptionOutput; std::string OptionSource; std::string OptionLanguage; + std::string OptionTargetLabels; std::string OptionTargetName; std::string OptionTargetType; std::string OptionBuildDir; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index e2a0f2193c..58bb69903c 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -2041,6 +2041,14 @@ std::vector cmGeneratorTarget::GetAppleArchs( return std::move(archList.data()); } +const std::string& cmGeneratorTarget::GetTargetLabelsString() +{ + this->targetLabelsString = this->GetSafeProperty("LABELS"); + std::replace(this->targetLabelsString.begin(), + this->targetLabelsString.end(), ';', ','); + return this->targetLabelsString; +} + namespace { bool IsSupportedClassifiedFlagsLanguage(std::string const& lang) @@ -2305,6 +2313,7 @@ cmGeneratorTarget::GetClassifiedFlagsForSource(cmSourceFile const* sf, cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(this->GetType()).c_str(); + vars.CMTargetLabels = this->GetTargetLabelsString().c_str(); vars.Language = lang.c_str(); auto const sfPath = this->LocalGenerator->ConvertToOutputFormat( diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index f2ff038ffc..e2d7e488ed 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -402,6 +402,8 @@ public: cmLocalGenerator* LocalGenerator; cmGlobalGenerator const* GlobalGenerator; + std::string targetLabelsString; + struct ModuleDefinitionInfo { std::string DefFile; @@ -514,6 +516,8 @@ public: std::vector GetAppleArchs(std::string const& config, cm::optional lang) const; + const std::string& GetTargetLabelsString(); + // The classification of the flag. enum class FlagClassification { diff --git a/Source/cmInstrumentation.cxx b/Source/cmInstrumentation.cxx index c7147c6ae8..bd0d16d2dc 100644 --- a/Source/cmInstrumentation.cxx +++ b/Source/cmInstrumentation.cxx @@ -425,6 +425,9 @@ int cmInstrumentation::InstrumentCommand( } if (arrayOptions.has_value()) { for (auto const& item : arrayOptions.value()) { + if (item.first == "targetLabels" && command_type != "link") { + continue; + } root[item.first] = Json::arrayValue; std::stringstream ss(item.second); std::string element; diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 7c0731926d..2847340d25 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -994,6 +994,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( vars.CMTargetName = target->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(target->GetType()).c_str(); + vars.CMTargetLabels = target->GetTargetLabelsString().c_str(); std::string output; const std::vector& outputs = ccg.GetOutputs(); for (size_t i = 0; i < outputs.size(); ++i) { diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index e24f2b75be..3dacc62305 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -537,6 +537,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.CMTargetName = this->GeneratorTarget->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str(); + vars.CMTargetLabels = + this->GeneratorTarget->GetTargetLabelsString().c_str(); vars.Language = linkLanguage.c_str(); vars.Linker = linker.c_str(); vars.AIXExports = aixExports.c_str(); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 746ee50f93..1b2a37e572 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -781,6 +781,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.CMTargetName = this->GeneratorTarget->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str(); + vars.CMTargetLabels = + this->GeneratorTarget->GetTargetLabelsString().c_str(); vars.Language = linkLanguage.c_str(); vars.Linker = linker.c_str(); vars.AIXExports = aixExports.c_str(); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 8098d7021a..5f4cddb5c1 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -931,6 +931,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( vars.CMTargetName = this->GeneratorTarget->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str(); + vars.CMTargetLabels = this->GeneratorTarget->GetTargetLabelsString().c_str(); vars.Language = lang.c_str(); vars.Target = targetOutPathReal.c_str(); vars.TargetPDB = targetOutPathPDB.c_str(); @@ -1694,7 +1695,7 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule( vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str(); - + vars.CMTargetLabels = this->GeneratorTarget->GetTargetLabelsString().c_str(); vars.Language = "CUDA"; vars.Object = output.c_str(); vars.Fatbinary = fatbinaryOutput.c_str(); diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 8b340453a5..cde90c209b 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -293,6 +293,8 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkRule( vars.CMTargetType = cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) .c_str(); + vars.CMTargetLabels = + this->GetGeneratorTarget()->GetTargetLabelsString().c_str(); vars.Language = "CUDA"; std::string linker = @@ -400,6 +402,8 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules( vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str(); + vars.CMTargetLabels = + this->GetGeneratorTarget()->GetTargetLabelsString().c_str(); vars.Language = "CUDA"; vars.Object = "$out"; @@ -451,6 +455,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str(); + vars.CMTargetLabels = + this->GetGeneratorTarget()->GetTargetLabelsString().c_str(); std::string linker = this->GetGeneratorTarget()->GetLinkerTool(config); vars.Linker = linker.c_str(); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index d2fb5b57fb..319106f8f5 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -623,6 +623,7 @@ cmNinjaRule GetScanRule( cmRulePlaceholderExpander::RuleVariables scanVars; scanVars.CMTargetName = vars.CMTargetName; scanVars.CMTargetType = vars.CMTargetType; + scanVars.CMTargetLabels = vars.CMTargetLabels; scanVars.Language = vars.Language; scanVars.Object = "$OBJ_FILE"; scanVars.PreprocessedSource = ppFileName.c_str(); @@ -681,6 +682,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str(); + vars.CMTargetLabels = + this->GetGeneratorTarget()->GetTargetLabelsString().c_str(); vars.Language = lang.c_str(); vars.Source = "$in"; vars.Object = "$out"; diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index ce41c8ae5b..4420e38843 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -261,6 +261,13 @@ std::string cmRulePlaceholderExpander::ExpandVariable( return this->ReplaceValues->CMTargetType; } } + if (variable == "TARGET_LABELS") { + if (this->ReplaceValues->CMTargetLabels) { + return this->ReplaceValues->CMTargetLabels; + } + return ""; + } + if (this->ReplaceValues->Output) { if (variable == "OUTPUT") { return this->ReplaceValues->Output; diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index d2a88e0b47..9b131fb7d7 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -32,6 +32,7 @@ public: { const char* CMTargetName = nullptr; const char* CMTargetType = nullptr; + const char* CMTargetLabels = nullptr; const char* TargetPDB = nullptr; const char* TargetCompilePDB = nullptr; const char* TargetVersionMajor = nullptr; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 95f4a929d6..86fcaf9cd6 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -2703,9 +2703,10 @@ int cmake::ActualConfigure() "--output --source --language -- ")); this->State->SetGlobalProperty( "RULE_LAUNCH_LINK", - cmStrCat(launcher, "--command-type link", common_args, - "--output --target-type ", - "--language -- ")); + cmStrCat( + launcher, "--command-type link", common_args, + "--output --target-type ", + "--language --target-labels \"\" -- ")); this->State->SetGlobalProperty( "RULE_LAUNCH_CUSTOM", cmStrCat(launcher, "--command-type custom", common_args, diff --git a/Tests/RunCMake/Instrumentation/check-data-dir.cmake b/Tests/RunCMake/Instrumentation/check-data-dir.cmake index 5776ce0e28..fb3ca8e6f3 100644 --- a/Tests/RunCMake/Instrumentation/check-data-dir.cmake +++ b/Tests/RunCMake/Instrumentation/check-data-dir.cmake @@ -8,6 +8,8 @@ endif() set(FOUND_SNIPPETS "") foreach(snippet ${snippets}) + get_filename_component(filename ${snippet} NAME) + read_json(${snippet} contents) # Verify snippet file is valid @@ -19,7 +21,7 @@ foreach(snippet ${snippets}) endif() # Verify target - string(JSON target ERROR_VARIABLE noTarget GET ${contents} target) + string(JSON target ERROR_VARIABLE noTarget GET "${contents}" target) if (NOT target MATCHES NOTFOUND) set(targets "main;lib;customTarget;TARGET_NAME") if (NOT ${target} IN_LIST targets) @@ -28,16 +30,16 @@ foreach(snippet ${snippets}) endif() # Verify output - string(JSON result GET ${contents} result) + string(JSON result GET "${contents}" result) if (NOT ${result} EQUAL 0) snippet_error(${snippet} "Compile command had non-0 result") endif() # Verify contents of compile-* Snippets - if (snippet MATCHES ^compile-) - string(JSON target GET ${contents} target) - string(JSON source GET ${contents} source) - string(JSON language GET ${contents} language) + if (filename MATCHES ^compile-) + string(JSON target GET "${contents}" target) + string(JSON source GET "${contents}" source) + string(JSON language GET "${contents}" language) if (NOT language MATCHES "C\\+\\+") snippet_error(${snippet} "Expected C++ compile language") endif() @@ -47,33 +49,53 @@ foreach(snippet ${snippets}) endif() # Verify contents of link-* Snippets - if (snippet MATCHES ^link-) - string(JSON target GET ${contents} target) - string(JSON targetType GET ${contents} targetType) + if (filename MATCHES ^link-) + string(JSON target GET "${contents}" target) + string(JSON targetType GET "${contents}" targetType) + string(JSON targetLabels GET "${contents}" targetLabels) if (target MATCHES main) if (NOT targetType MATCHES "EXECUTABLE") snippet_error(${snippet} "Expected EXECUTABLE, target type was ${targetType}") endif() + string(JSON nlabels LENGTH "${targetLabels}") + if (NOT nlabels STREQUAL 2) + snippet_error(${snippet} "Missing Target Labels for: ${target}") + else() + string(JSON label1 GET "${contents}" targetLabels 0) + string(JSON label2 GET "${contents}" targetLabels 1) + if (NOT label1 MATCHES "label1" OR NOT label2 MATCHES "label2") + snippet_error(${snippet} "Missing Target Labels for: ${target}") + endif() + endif() endif() if (target MATCHES lib) if (NOT targetType MATCHES "STATIC_LIBRARY") snippet_error(${snippet} "Expected STATIC_LIBRARY, target type was ${targetType}") endif() + string(JSON nlabels LENGTH "${targetLabels}") + if (NOT nlabels STREQUAL 1) + snippet_error(${snippet} "Missing Target Labels for: ${target}") + else() + string(JSON label ERROR_VARIABLE noLabels GET "${contents}" targetLabels 0) + if (NOT label MATCHES "label3") + snippet_error(${snippet} "Missing Target Labels for: ${target}") + endif() + endif() endif() endif() # Verify contents of custom-* Snippets - if (snippet MATCHES ^custom-) - string(JSON outputs GET ${contents} outputs) + if (filename MATCHES ^custom-) + string(JSON outputs GET "${contents}" outputs) if (NOT output1 MATCHES "output1" OR NOT output2 MATCHES "output2") snippet_error(${snippet} "Custom command missing outputs") endif() endif() # Verify contents of test-* Snippets - if (snippet MATCHES ^test-) - string(JSON testName GET ${contents} testName) - if (NOT testName EQUAL "test") + if (filename MATCHES ^test-) + string(JSON testName GET "${contents}" testName) + if (NOT testName STREQUAL "test") snippet_error(${snippet} "Unexpected testName: ${testName}") endif() endif() diff --git a/Tests/RunCMake/Instrumentation/hook.cmake b/Tests/RunCMake/Instrumentation/hook.cmake index d3be3a41ba..973e7d89c7 100644 --- a/Tests/RunCMake/Instrumentation/hook.cmake +++ b/Tests/RunCMake/Instrumentation/hook.cmake @@ -6,7 +6,7 @@ if (NOT ${CMAKE_ARGV3}) set(hasStaticInfo "UNEXPECTED") endif() read_json(${index} contents) -string(JSON hook GET ${contents} hook) +string(JSON hook GET "${contents}" hook) # Output is verified by *-stdout.txt files that the HOOK is run message(STATUS ${hook}) @@ -19,7 +19,7 @@ endmacro() macro(has_key key json) cmake_parse_arguments(ARG "UNEXPECTED" "" "" ${ARGN}) unset(missingKey) - string(JSON ${key} ERROR_VARIABLE missingKey GET ${json} ${key}) + string(JSON ${key} ERROR_VARIABLE missingKey GET "${json}" ${key}) if (NOT ARG_UNEXPECTED AND NOT "${missingKey}" MATCHES NOTFOUND) add_error("\nKey \"${key}\" not in index:\n${json}") elseif(ARG_UNEXPECTED AND "${missingKey}" MATCHES NOTFOUND) @@ -39,7 +39,7 @@ endif() string(JSON length LENGTH ${snippets}) math(EXPR length ${length}-1) foreach(i RANGE ${length}) - string(JSON filename GET ${snippets} ${i}) + string(JSON filename GET "${snippets}" ${i}) if (NOT EXISTS ${dataDir}/${filename}) add_error("Listed snippet: ${dataDir}/${filename} does not exist") endif() diff --git a/Tests/RunCMake/Instrumentation/verify-snippet.cmake b/Tests/RunCMake/Instrumentation/verify-snippet.cmake index 5f23bf2392..5c93c1ed69 100644 --- a/Tests/RunCMake/Instrumentation/verify-snippet.cmake +++ b/Tests/RunCMake/Instrumentation/verify-snippet.cmake @@ -9,44 +9,46 @@ macro(snippet_error snippet error) endmacro() macro(has_key snippet json key) - string(JSON data ERROR_VARIABLE missingKey GET ${json} ${key}) + string(JSON data ERROR_VARIABLE missingKey GET "${json}" ${key}) if (NOT ${missingKey} MATCHES NOTFOUND) snippet_error(${snippet} "Missing ${key}") endif() endmacro() macro(has_not_key snippet json key) - string(JSON data ERROR_VARIABLE missingKey GET ${json} ${key}) + string(JSON data ERROR_VARIABLE missingKey GET "${json}" ${key}) if (${missingKey} MATCHES NOTFOUND) snippet_error(${snippet} "Has unexpected ${key}") endif() endmacro() macro(snippet_has_fields snippet contents) + get_filename_component(filename ${snippet} NAME) has_key(${snippet} ${contents} command) has_key(${snippet} ${contents} role) has_key(${snippet} ${contents} result) - if (snippet MATCHES ^link-*) + if (filename MATCHES ^link-*) has_key(${snippet} ${contents} target) has_key(${snippet} ${contents} outputs) has_key(${snippet} ${contents} outputSizes) has_key(${snippet} ${contents} targetType) - elseif (snippet MATCHES ^compile-*) + has_key(${snippet} ${contents} targetLabels) + elseif (filename MATCHES ^compile-*) has_key(${snippet} ${contents} target) has_key(${snippet} ${contents} outputs) has_key(${snippet} ${contents} outputSizes) has_key(${snippet} ${contents} source) has_key(${snippet} ${contents} language) - elseif (snippet MATCHES ^custom-*) + elseif (filename MATCHES ^custom-*) has_key(${snippet} ${contents} target) has_key(${snippet} ${contents} outputs) has_key(${snippet} ${contents} outputSizes) - elseif (snippet MATCHES ^test-*) + elseif (filename MATCHES ^test-*) has_key(${snippet} ${contents} testName) endif() if(ARGS_DYNAMIC_QUERY) has_key(${snippet} ${contents} dynamicSystemInformation) - string(JSON dynamicSystemInfo ERROR_VARIABLE noInfo GET ${contents} dynamicSystemInformation) + string(JSON dynamicSystemInfo ERROR_VARIABLE noInfo GET "${contents}" dynamicSystemInformation) if (noInfo MATCHES NOTFOUND) has_key(${snippet} ${dynamicSystemInfo} beforeCPULoadAverage) has_key(${snippet} ${dynamicSystemInfo} beforeHostMemoryUsed) @@ -55,7 +57,7 @@ macro(snippet_has_fields snippet contents) endif() else() has_not_key(${snippet} ${contents} dynamicSystemInformation) - string(JSON dynamicSystemInfo ERROR_VARIABLE noInfo GET ${contents} dynamicSystemInformation) + string(JSON dynamicSystemInfo ERROR_VARIABLE noInfo GET "${contents}" dynamicSystemInformation) if (noInfo MATCHES NOTFOUND) has_not_key(${snippet} ${dynamicSystemInfo} beforeCPULoadAverage) has_not_key(${snippet} ${dynamicSystemInfo} beforeHostMemoryUsed) @@ -66,8 +68,8 @@ macro(snippet_has_fields snippet contents) endmacro() macro(snippet_valid_timing contents) - string(JSON start GET ${contents} timeStart) - string(JSON duration GET ${contents} duration) + string(JSON start GET "${contents}" timeStart) + string(JSON duration GET "${contents}" duration) if (${start} LESS 0) snippet_error(${snippet} "Negative time start: ${start}") endif() @@ -79,18 +81,18 @@ endmacro() macro(verify_snippet snippet contents) snippet_has_fields(${snippet} ${contents}) snippet_valid_timing(${contents}) - string(JSON version GET ${contents} version) + string(JSON version GET "${contents}" version) if (NOT ${version} EQUAL 1) snippet_error(${snippet} "Version must be 1, got: ${version}") endif() - string(JSON role GET ${contents} role) + string(JSON role GET "${contents}" role) get_filename_component(filename ${snippet} NAME) if (NOT ${filename} MATCHES ^${role}-) snippet_error(${snippet} "Role \"${role}\" doesn't match snippet filename") endif() - string(JSON outputs ERROR_VARIABLE noOutputs GET ${contents} outputs) + string(JSON outputs ERROR_VARIABLE noOutputs GET "${contents}" outputs) if (NOT outputs MATCHES NOTFOUND) - string(JSON outputSizes ERROR_VARIABLE noOutputSizes GET ${contents} outputSizes) + string(JSON outputSizes ERROR_VARIABLE noOutputSizes GET "${contents}" outputSizes) list(LENGTH outputs outputsLen) list(LENGTH outputSizes outputSizesLen) if (outputSizes MATCHES NOTFOUND OR NOT outputsLen EQUAL outputSizesLen)