diff --git a/Help/manual/cmake-instrumentation.7.rst b/Help/manual/cmake-instrumentation.7.rst index 9a6b181467..d21fc6607a 100644 --- a/Help/manual/cmake-instrumentation.7.rst +++ b/Help/manual/cmake-instrumentation.7.rst @@ -503,7 +503,9 @@ generated whenever `Indexing`_ occurs and deleted after any user-specified ``staticSystemInformation`` Specifies the static information collected about the host machine - CMake is being run from. Only included when enabled by the `v1 Query Files`_. + CMake is being run from. If CMake is unable to determine the value of any + given field, it will be ``null``. Only included when enabled by the + `v1 Query Files`_. * ``OSName`` * ``OSPlatform`` diff --git a/Source/cmInstrumentation.cxx b/Source/cmInstrumentation.cxx index 69f83a41fa..d19dae0bf9 100644 --- a/Source/cmInstrumentation.cxx +++ b/Source/cmInstrumentation.cxx @@ -492,6 +492,14 @@ void cmInstrumentation::InsertStaticSystemInformation(Json::Value& root) static_cast(info.GetTotalVirtualMemory()); infoRoot["vendorID"] = info.GetVendorID(); infoRoot["vendorString"] = info.GetVendorString(); + + // Record fields unable to be determined as null JSON objects. + for (std::string const& field : infoRoot.getMemberNames()) { + if ((infoRoot[field].isNumeric() && infoRoot[field].asInt64() <= 0) || + (infoRoot[field].isString() && infoRoot[field].asString().empty())) { + infoRoot[field] = Json::nullValue; + } + } root["staticSystemInformation"] = infoRoot; } diff --git a/Tests/RunCMake/Instrumentation/hook.cmake b/Tests/RunCMake/Instrumentation/hook.cmake index 84e040edc6..47ee35158c 100644 --- a/Tests/RunCMake/Instrumentation/hook.cmake +++ b/Tests/RunCMake/Instrumentation/hook.cmake @@ -108,6 +108,53 @@ if (NOT hasStaticInfo STREQUAL UNEXPECTED) json_has_key("${index}" "${staticSystemInformation}" totalVirtualMemory ${hasStaticInfo}) json_has_key("${index}" "${staticSystemInformation}" vendorID ${hasStaticInfo}) json_has_key("${index}" "${staticSystemInformation}" vendorString ${hasStaticInfo}) + + # FIXME(#27545): We currently do not guarantee that the fields above which + # output strings are non-empty. `vendorString` and `processorName` especially + # have shown issues on some platforms. This test is logically equivalent to + # RunCMake.cmake_host_system_information, which uses the same underlying + # implementation. + set(string_fields + OSName + OSPlatform + OSRelease + OSVersion + familyId + hostname + modelId + vendorID + vendorString + ) + foreach (field IN LISTS string_fields) + string(JSON ${field}_type TYPE "${staticSystemInformation}" ${field}) + if (NOT "${${field}_type}" STREQUAL "NULL" AND NOT "${${field}_type}" STREQUAL "STRING") + add_error("Got bad type '${${field}_type}' for field '${field}': ${${field}}") + endif() + if ("${${field}_type}" STREQUAL "STRING" AND ${field} STREQUAL "") + add_error("Got empty string for field '${field}'") + endif() + endforeach() + + # We guarantee that the numeric fields are either indeed numeric, or else + # null. + set(numeric_fields + numberOfLogicalCPU + numberOfPhysicalCPU + processorAPICID + processorCacheSize + processorClockFrequency + totalPhysicalMemory + totalVirtualMemory + ) + foreach (field IN LISTS numeric_fields) + string(JSON ${field}_type TYPE "${staticSystemInformation}" ${field}) + if (NOT "${${field}_type}" STREQUAL "NULL" AND NOT "${${field}_type}" STREQUAL "NUMBER") + add_error("Got bad type '${${field}_type}' for field '${field}': ${${field}}") + endif() + if ("${${field}_type}" STREQUAL "NUMBER" AND ${field} LESS_EQUAL 0) + add_error("Got bad value for field '${field}': ${${field}}") + endif() + endforeach() endif() get_filename_component(v1 ${dataDir} DIRECTORY) diff --git a/Tests/RunCMake/Instrumentation/json.cmake b/Tests/RunCMake/Instrumentation/json.cmake index a01a2a96c9..9092af47cf 100644 --- a/Tests/RunCMake/Instrumentation/json.cmake +++ b/Tests/RunCMake/Instrumentation/json.cmake @@ -41,6 +41,7 @@ function(json_missing_key file json key) endfunction() # Check if the JSON string `json` has `key` and its value matches `expected`. +# If successful, return its value in `key`. function(json_assert_key file json key expected) string(JSON data ERROR_VARIABLE missingKey GET "${json}" ${key}) if (NOT missingKey MATCHES NOTFOUND) @@ -52,6 +53,7 @@ function(json_assert_key file json key expected) "Unexpected data in custom content file:\nGot ${data}, Expected ${expected}." ) endif() + set(${key} ${data} PARENT_SCOPE) return(PROPAGATE RunCMake_TEST_FAILED ERROR_MESSAGE) endfunction()