Browse Source

Merge topic 'instrumentation-target-content'

97adbc91fa instrumentation: Move target data into content files

Acked-by: Kitware Robot <[email protected]>
Tested-by: buildbot <[email protected]>
Merge-request: !11251
Brad King 2 weeks ago
parent
commit
caf01b88bc

+ 8 - 9
Help/command/cmake_instrumentation.rst

@@ -37,15 +37,14 @@ Whenever ``cmake_instrumentation`` is invoked, a query file is generated in
 ``<build>/.cmake/instrumentation/v1/query/generated`` to enable instrumentation
 with the provided arguments.
 
-.. _`cmake_instrumentation Configure Content`:
+.. _`cmake_instrumentation CUSTOM_CONTENT`:
 
-Custom Configure Content
-^^^^^^^^^^^^^^^^^^^^^^^^
+Custom CMake Content
+^^^^^^^^^^^^^^^^^^^^
 
 The ``CUSTOM_CONTENT`` argument specifies certain data from configure time to
-include in each :ref:`cmake-instrumentation v1 Snippet File` that
-corresponds to the configure step associated with the command. This may be used
-to associate instrumentation data with certain information about its
+include in each :ref:`cmake-instrumentation v1 CMake Content File`. This
+may be used to associate instrumentation data with certain information about its
 configuration, such as the optimization level or whether it is part of a
 coverage build.
 
@@ -102,12 +101,12 @@ equivalent JSON query file.
     ]
   }
 
-This will also result in a configure content JSON being reported in each
-:ref:`cmake-instrumentation v1 Snippet File` with the following contents:
+This will also result in the following content included in each
+:ref:`cmake-instrumentation v1 CMake Content File`:
 
 .. code-block:: json
 
-  {
+  "custom": {
     "myString": "string",
     "myList": [
       "item1", "item2"

+ 43 - 20
Help/manual/cmake-instrumentation.7.rst

@@ -127,6 +127,10 @@ by setting :envvar:`CTEST_USE_VERBOSE_INSTRUMENTATION` to 1.
 Alternatively, you can use the `v1 Query Files`_ to enable instrumentation for
 CDash using the ``cdashSubmit`` and ``cdashVerbose`` options.
 
+In order for the submitted ``Build.xml`` file to group the snippet files
+correctly, all configure and build commands should be executed with CTest in
+Dashboard Client mode.
+
 .. _`cmake-instrumentation API v1`:
 
 API v1
@@ -164,7 +168,7 @@ subdirectories:
 
 ``data/content/``
   A subset of the collected data, containing any
-  :ref:`cmake_instrumentation Configure Content` files.
+  `v1 CMake Content Files <v1 CMake Content File_>`_.
 
 ``data/trace/``
   A subset of the collected data, containing the `Google Trace File`_ created
@@ -302,9 +306,9 @@ Data version specifies the contents of the output files generated by the CMake
 instrumentation API as part of the `Data Collection`_ and `Indexing`_. A new
 version number will be created whenever previously included data is removed or
 reformatted such that scripts written to parse this data may become
-incompatible with the new format. There are three types of data files generated:
-the `v1 Snippet File`_, the `v1 Index File`_, and the `Google Trace File`_.
-When using the `API v1`_, these files live in
+incompatible with the new format. There are four types of data files generated:
+the `v1 Snippet File`_, `v1 Index File`_, `v1 CMake Content File`_, and the
+`Google Trace File`_. When using the `API v1`_, these files live in
 ``<build>/.cmake/instrumentation/v1/data/`` under the project build tree.
 
 .. _`cmake-instrumentation v1 Snippet File`:
@@ -359,17 +363,9 @@ and contain the following data:
     * ``test``: a single test executed by CTest
 
   ``target``
-    The CMake target associated with the command. Included when ``role`` is
-    ``compile``, or ``link``, and when ``role`` is ``custom`` and the custom
-    command is attached to a target with :ref:`add_custom_command(TARGET)`.
-
-  ``targetType``
-    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``.
+    The CMake target associated with the command. Only included when ``role`` is
+    ``compile`` or ``link``. In conjunction with ``cmakeContent``, this can
+    be used to look up the target type and labels.
 
   ``timeStart``
     Time at which the command started, expressed as the number of milliseconds
@@ -422,10 +418,10 @@ and contain the following data:
       The Average CPU Load at ``timeStart + duration``, or ``null`` if it cannot
       be determined.
 
-  ``configureContent``
-    The path to a :ref:`cmake_instrumentation Configure Content` file located
-    under ``data``, which may contain information about the CMake configure
-    step corresponding to this data.
+  ``cmakeContent``
+    The path to a `v1 CMake Content` file located under ``data``, which
+    contains information about the CMake configure and generate steps
+    responsible for generating the ``command`` in this snippet.
 
 Example:
 
@@ -451,7 +447,7 @@ Example:
     },
     "timeStart" : 1737053448177,
     "duration" : 31,
-    "configureContent" : "content/configure-2025-07-11T12-46-32-0572.json"
+    "cmakeContent" : "content/cmake-2025-07-11T12-46-32-0572.json"
   }
 
 v1 Index File
@@ -534,6 +530,33 @@ Example:
     "trace": "trace/trace-<timestamp>.json"
   }
 
+.. _`cmake-instrumentation v1 CMake Content File`:
+
+v1 CMake Content File
+---------------------
+
+CMake content files contain information about the CMake configure and generate
+steps. Each `v1 Snippet File`_ provides the path to one of these files
+corresponding to the CMake invocation responsible for generating its command.
+
+Each CMake content file contains the following:
+
+  ``custom``
+    An object containing arbitrary JSON data specified by the user with the
+    :ref:`cmake_instrumentation CUSTOM_CONTENT` functionality of the
+    :command:`cmake_instrumentation` command.
+
+  ``targets``
+    An object containing CMake targets, indexed by name, that have corresponding
+    instrumentation data. Each target contains the following:
+
+    ``type``
+      The target type. One of ``EXECUTABLE``, ``STATIC_LIBRARY``,
+      ``SHARED_LIBRARY`` or ``OBJECT_LIBRARY``.
+
+    ``labels``
+      The :prop_tgt:`LABELS` property of the target.
+
 Google Trace File
 -----------------
 

+ 27 - 37
Source/CTest/cmCTestBuildHandler.cxx

@@ -626,48 +626,38 @@ void cmCTestBuildHandler::GenerateInstrumentationXML(cmXMLWriter& xml)
       xml.StartElement("Target");
       xml.Attribute("name", target_name);
 
-      // Check if we have a link snippet for this target.
-      cmsys::Directory target_dir;
-      if (!target_dir.Load(targets_dir.GetFilePath(i))) {
-        cmSystemTools::Error(
-          cmStrCat("Error loading directory ", targets_dir.GetFilePath(i)));
-      }
-      Json::Value link_item;
-      for (unsigned int j = 0; j < target_dir.GetNumberOfFiles(); j++) {
-        std::string fname = target_dir.GetFile(j);
-        if (fname.rfind("link-", 0) == 0) {
-          std::string fpath = target_dir.GetFilePath(j);
-          cmJSONState parseState = cmJSONState(fpath, &link_item);
-          if (!parseState.errors.empty()) {
-            cmSystemTools::Error(parseState.GetErrorMessage(true));
-            break;
-          }
-
-          if (!link_item.isObject()) {
-            std::string error_msg =
-              cmStrCat("Expected snippet ", fpath, " to contain an object");
-            cmSystemTools::Error(error_msg);
-            break;
-          }
+      // Load latest CMake content file
+      Json::Value target_data;
+      std::string cmake_content_file =
+        cmStrCat(CTest->GetInstrumentation().GetDataDir(), "/content/",
+                 this->CTest->GetInstrumentation().GetFileByTimestamp(
+                   cmInstrumentation::LatestOrOldest::Latest, "content"));
+      if (!cmake_content_file.empty() &&
+          cmSystemTools::FileExists(cmake_content_file)) {
+        Json::Value cmake_content;
+        cmJSONState parseState =
+          cmJSONState(cmake_content_file, &cmake_content);
+        if (!parseState.errors.empty()) {
+          cmSystemTools::Error(parseState.GetErrorMessage(true));
           break;
         }
+        if (cmake_content.isMember("targets")) {
+          target_data = cmake_content["targets"];
+        }
       }
-
-      // If so, parse targetType and targetLabels (optional) from it.
-      if (link_item.isMember("targetType")) {
-        target_type = link_item["targetType"].asString();
-      }
-
-      xml.Attribute("type", target_type);
-
-      if (link_item.isMember("targetLabels") &&
-          !link_item["targetLabels"].empty()) {
-        xml.StartElement("Labels");
-        for (auto const& json_label_item : link_item["targetLabels"]) {
-          xml.Element("Label", json_label_item.asString());
+      // Extract targetType and targetLabels
+      if (target_data.isObject() && target_data.isMember(target_name)) {
+        target_type = target_data[target_name]["type"].asString();
+        if (!target_data[target_name]["labels"].empty()) {
+          xml.StartElement("Labels");
+          for (auto const& json_label_item :
+               target_data[target_name]["labels"]) {
+            xml.Element("Label", json_label_item.asString());
+          }
+          xml.EndElement(); // Labels
         }
-        xml.EndElement(); // Labels
       }
+      xml.Attribute("type", target_type);
 
       // Write instrumendation data for this target.
       std::string target_subdir = cmStrCat("build/targets/", target_name);

+ 0 - 4
Source/cmFastbuildNormalTargetGenerator.cxx

@@ -257,8 +257,6 @@ bool cmFastbuildNormalTargetGenerator::DetectBaseLinkerCommand(
   cmRulePlaceholderExpander::RuleVariables vars;
   vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
   vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str();
-  vars.CMTargetLabels =
-    this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
   vars.Config = Config.c_str();
   vars.Language = linkLanguage.c_str();
   std::string const manifests =
@@ -1133,8 +1131,6 @@ cmFastbuildNormalTargetGenerator::ComputeRuleVariables() const
   compileObjectVars.CMTargetName = GeneratorTarget->GetName().c_str();
   compileObjectVars.CMTargetType =
     cmState::GetTargetTypeName(GeneratorTarget->GetType()).c_str();
-  compileObjectVars.CMTargetLabels =
-    this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
   compileObjectVars.Source = FASTBUILD_1_INPUT_PLACEHOLDER;
   compileObjectVars.Object = FASTBUILD_2_INPUT_PLACEHOLDER;
   compileObjectVars.ObjectDir =

+ 0 - 9
Source/cmGeneratorTarget.cxx

@@ -2095,14 +2095,6 @@ std::vector<std::string> cmGeneratorTarget::GetAppleArchs(
   return std::move(archList.data());
 }
 
-std::string const& 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)
@@ -2367,7 +2359,6 @@ 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(

+ 0 - 2
Source/cmGeneratorTarget.h

@@ -535,8 +535,6 @@ public:
   std::vector<std::string> GetAppleArchs(std::string const& config,
                                          cm::optional<std::string> lang) const;
 
-  std::string const& GetTargetLabelsString();
-
   // The classification of the flag.
   enum class FlagClassification
   {

+ 86 - 28
Source/cmInstrumentation.cxx

@@ -11,6 +11,7 @@
 
 #include <cm/memory>
 #include <cm/optional>
+#include <cmext/algorithm>
 
 #include <cm3p/json/reader.h>
 #include <cm3p/json/version.h>
@@ -27,8 +28,13 @@
 #include "cmExperimental.h"
 #include "cmFileLock.h"
 #include "cmFileLockResult.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
 #include "cmInstrumentationQuery.h"
 #include "cmJSONState.h"
+#include "cmList.h"
+#include "cmLocalGenerator.h"
+#include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTimestamp.h"
@@ -94,6 +100,7 @@ cmInstrumentation::cmInstrumentation(std::string const& binary_dir,
   this->timingDirv1 =
     cmStrCat(this->binaryDir, "/.cmake/instrumentation-", uuid, "/v1");
   this->cdashDir = cmStrCat(this->timingDirv1, "/cdash");
+  this->dataDir = cmStrCat(this->timingDirv1, "/data");
   if (cm::optional<std::string> configDir =
         cmSystemTools::GetCMakeConfigDirectory()) {
     this->userTimingDirv1 =
@@ -221,20 +228,45 @@ void cmInstrumentation::AddCustomContent(std::string const& name,
   this->customContent[name] = contents;
 }
 
-void cmInstrumentation::WriteCustomContent()
+void cmInstrumentation::WriteCMakeContent(
+  std::unique_ptr<cmGlobalGenerator> const& gg)
 {
-  if (!this->customContent.isNull()) {
-    this->WriteInstrumentationJson(
-      this->customContent, "data/content",
-      cmStrCat("configure-", this->ComputeSuffixTime(), ".json"));
+  Json::Value root;
+  root["targets"] = this->DumpTargets(gg);
+  root["custom"] = this->customContent;
+  this->WriteInstrumentationJson(
+    root, "data/content",
+    cmStrCat("cmake-", this->ComputeSuffixTime(), ".json"));
+}
+
+Json::Value cmInstrumentation::DumpTargets(
+  std::unique_ptr<cmGlobalGenerator> const& gg)
+{
+  Json::Value targets = Json::objectValue;
+  std::vector<cmGeneratorTarget*> targetList;
+  for (auto const& lg : gg->GetLocalGenerators()) {
+    cm::append(targetList, lg->GetGeneratorTargets());
   }
+  for (cmGeneratorTarget* gt : targetList) {
+    if (this->IsInstrumentableTargetType(gt->GetType())) {
+      Json::Value target = Json::objectValue;
+      auto labels = gt->GetSafeProperty("LABELS");
+      target["labels"] = Json::arrayValue;
+      for (auto const& item : cmList(labels)) {
+        target["labels"].append(item);
+      }
+      target["type"] = cmState::GetTargetTypeName(gt->GetType()).c_str();
+      targets[gt->GetName()] = target;
+    }
+  }
+  return targets;
 }
 
 std::string cmInstrumentation::GetFileByTimestamp(
   cmInstrumentation::LatestOrOldest order, std::string const& dataSubdir,
   std::string const& exclude)
 {
-  std::string fullDir = cmStrCat(this->timingDirv1, "/data/", dataSubdir);
+  std::string fullDir = cmStrCat(this->dataDir, '/', dataSubdir);
   std::string result;
   if (cmSystemTools::FileExists(fullDir)) {
     cmsys::Directory d;
@@ -255,12 +287,11 @@ std::string cmInstrumentation::GetFileByTimestamp(
 
 void cmInstrumentation::RemoveOldFiles(std::string const& dataSubdir)
 {
-  std::string const dataSubdirPath =
-    cmStrCat(this->timingDirv1, "/data/", dataSubdir);
+  std::string const dataSubdirPath = cmStrCat(this->dataDir, '/', dataSubdir);
   std::string oldIndex =
     this->GetFileByTimestamp(LatestOrOldest::Oldest, "index");
   if (!oldIndex.empty()) {
-    oldIndex = cmStrCat(this->timingDirv1, "/data/index/", oldIndex);
+    oldIndex = cmStrCat(this->dataDir, "/index/", oldIndex);
   }
   if (cmSystemTools::FileExists(dataSubdirPath)) {
     std::string latestFile =
@@ -316,10 +347,9 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
   }
 
   // Touch index file immediately to claim snippets
-  std::string const& directory = cmStrCat(this->timingDirv1, "/data");
   std::string suffix_time = ComputeSuffixTime();
   std::string const& index_name = cmStrCat("index-", suffix_time, ".json");
-  std::string index_path = cmStrCat(directory, "/index/", index_name);
+  std::string index_path = cmStrCat(this->dataDir, "/index/", index_name);
   cmSystemTools::Touch(index_path, true);
 
   // Gather Snippets
@@ -328,7 +358,7 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
   cmsys::Directory d;
   std::string last_index_name =
     this->GetFileByTimestamp(LatestOrOldest::Latest, "index", index_name);
-  if (d.Load(directory)) {
+  if (d.Load(this->dataDir)) {
     for (unsigned int i = 0; i < d.GetNumberOfFiles(); i++) {
       std::string fpath = d.GetFilePath(i);
       std::string fname = d.GetFile(i);
@@ -343,7 +373,7 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
   Json::Value index(Json::objectValue);
   index["snippets"] = Json::arrayValue;
   index["hook"] = cmInstrumentationQuery::HookString[hook];
-  index["dataDir"] = directory;
+  index["dataDir"] = this->dataDir;
   index["buildDir"] = this->binaryDir;
   index["version"] = 1;
   if (this->HasOption(
@@ -356,7 +386,7 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
     } else {
       int compare;
       std::string last_index_path =
-        cmStrCat(directory, "/index/", last_index_name);
+        cmStrCat(this->dataDir, "/index/", last_index_name);
       cmSystemTools::FileTimeCompare(file.second, last_index_path, &compare);
       if (compare == 1) {
         index["snippets"].append(file.first);
@@ -383,12 +413,12 @@ int cmInstrumentation::CollectTimingData(cmInstrumentationQuery::Hook hook)
 
   // Special case for CDash collation
   if (this->HasOption(cmInstrumentationQuery::Option::CDashSubmit)) {
-    this->PrepareDataForCDash(directory, index_path);
+    this->PrepareDataForCDash(this->dataDir, index_path);
   }
 
   // Delete files
   for (auto const& f : index["snippets"]) {
-    cmSystemTools::RemoveFile(cmStrCat(directory, '/', f.asString()));
+    cmSystemTools::RemoveFile(cmStrCat(this->dataDir, '/', f.asString()));
   }
   cmSystemTools::RemoveFile(index_path);
 
@@ -605,11 +635,6 @@ int cmInstrumentation::InstrumentCommand(
   int ret = callback();
   root["result"] = ret;
 
-  // Write configure content if command was configure
-  if (command_type == "configure") {
-    this->WriteCustomContent();
-  }
-
   // Exit early if configure didn't generate a query
   if (reloadQueriesAfterCommand == LoadQueriesAfter::Yes) {
     this->LoadQueries();
@@ -675,11 +700,16 @@ int cmInstrumentation::InstrumentCommand(
   root["role"] = command_type;
   root["workingDir"] = cmSystemTools::GetLogicalWorkingDirectory();
 
-  // Add custom configure content
-  std::string contentFile =
-    this->GetFileByTimestamp(LatestOrOldest::Latest, "content");
-  if (!contentFile.empty()) {
-    root["configureContent"] = cmStrCat("content/", contentFile);
+  auto addCMakeContent = [this](Json::Value& root_) -> void {
+    std::string contentFile =
+      this->GetFileByTimestamp(LatestOrOldest::Latest, "content");
+    if (!contentFile.empty()) {
+      root_["cmakeContent"] = cmStrCat("content/", contentFile);
+    }
+  };
+  // Don't insert path to CMake content until generate time
+  if (command_type != "configure") {
+    addCMakeContent(root);
   }
 
   // Write Json
@@ -690,7 +720,21 @@ int cmInstrumentation::InstrumentCommand(
     command_type, '-',
     this->ComputeSuffixHash(cmStrCat(command_str, info.GetProcessId())), '-',
     this->ComputeSuffixTime(endTime), ".json");
-  this->WriteInstrumentationJson(root, "data", file_name);
+
+  // Don't write configure snippet until generate time
+  if (command_type == "configure") {
+    this->configureSnippetData = root;
+    this->configureSnippetName = file_name;
+  } else {
+    // Add reference to CMake content and write out configure snippet after
+    // generate
+    if (command_type == "generate") {
+      addCMakeContent(this->configureSnippetData);
+      this->WriteInstrumentationJson(this->configureSnippetData, "data",
+                                     this->configureSnippetName);
+    }
+    this->WriteInstrumentationJson(root, "data", file_name);
+  }
   return ret;
 }
 
@@ -736,6 +780,15 @@ std::string cmInstrumentation::ComputeSuffixTime(
   return ss.str();
 }
 
+bool cmInstrumentation::IsInstrumentableTargetType(
+  cmStateEnums::TargetType type)
+{
+  return type == cmStateEnums::TargetType::EXECUTABLE ||
+    type == cmStateEnums::TargetType::SHARED_LIBRARY ||
+    type == cmStateEnums::TargetType::STATIC_LIBRARY ||
+    type == cmStateEnums::TargetType::OBJECT_LIBRARY;
+}
+
 /*
  * Called by ctest --start-instrumentation.
  *
@@ -818,11 +871,16 @@ void cmInstrumentation::AddOption(cmInstrumentationQuery::Option option)
   this->options.insert(option);
 }
 
-std::string const& cmInstrumentation::GetCDashDir()
+std::string const& cmInstrumentation::GetCDashDir() const
 {
   return this->cdashDir;
 }
 
+std::string const& cmInstrumentation::GetDataDir() const
+{
+  return this->dataDir;
+}
+
 /** Copy the snippets referred to by an index file to a separate
  * directory where they will be parsed for submission to CDash.
  **/

+ 20 - 11
Source/cmInstrumentation.h

@@ -17,13 +17,16 @@
 #include <cm3p/json/value.h>
 #include <stddef.h>
 
-#include "cmFileLock.h"
 #ifndef CMAKE_BOOTSTRAP
 #  include <cmsys/SystemInformation.hxx>
 #endif
 #include <stdint.h>
 
+#include "cmFileLock.h"
 #include "cmInstrumentationQuery.h"
+#include "cmStateTypes.h"
+
+class cmGlobalGenerator;
 
 class cmInstrumentation
 {
@@ -61,7 +64,8 @@ public:
                       std::set<cmInstrumentationQuery::Hook> const& hooks,
                       std::vector<std::vector<std::string>> const& callback);
   void AddCustomContent(std::string const& name, Json::Value const& contents);
-  void WriteCustomContent();
+  void WriteCMakeContent(std::unique_ptr<cmGlobalGenerator> const& gg);
+  Json::Value DumpTargets(std::unique_ptr<cmGlobalGenerator> const& gg);
   void ClearGeneratedQueries();
   int CollectTimingData(cmInstrumentationQuery::Hook hook);
   int SpawnBuildDaemon();
@@ -70,7 +74,16 @@ public:
   void AddHook(cmInstrumentationQuery::Hook hook);
   void AddOption(cmInstrumentationQuery::Option option);
   bool HasErrors() const;
-  std::string const& GetCDashDir();
+  std::string const& GetCDashDir() const;
+  std::string const& GetDataDir() const;
+  enum LatestOrOldest
+  {
+    Latest,
+    Oldest
+  };
+  std::string GetFileByTimestamp(LatestOrOldest latestOrOldest,
+                                 std::string const& dataSubdir,
+                                 std::string const& exclude = "");
 
 private:
   Json::Value ReadJsonSnippet(std::string const& file_name);
@@ -89,6 +102,7 @@ private:
   static std::string ComputeSuffixHash(std::string const& command_str);
   static std::string ComputeSuffixTime(
     cm::optional<std::chrono::system_clock::time_point> time = cm::nullopt);
+  static bool IsInstrumentableTargetType(cmStateEnums::TargetType type);
   void PrepareDataForCDash(std::string const& data_dir,
                            std::string const& index_path);
   void RemoveOldFiles(std::string const& dataSubdir);
@@ -97,18 +111,11 @@ private:
                               Json::Value const& snippetData);
   size_t AssignTargetToTraceThread(std::vector<uint64_t>& workers,
                                    uint64_t timeStart, uint64_t duration);
-  enum LatestOrOldest
-  {
-    Latest,
-    Oldest
-  };
-  std::string GetFileByTimestamp(LatestOrOldest latestOrOldest,
-                                 std::string const& dataSubdir,
-                                 std::string const& exclude = "");
   std::string binaryDir;
   std::string timingDirv1;
   std::string userTimingDirv1;
   std::string cdashDir;
+  std::string dataDir;
   std::set<cmInstrumentationQuery::Option> options;
   std::set<cmInstrumentationQuery::Hook> hooks;
   std::vector<std::string> callbacks;
@@ -120,6 +127,8 @@ private:
   bool ranSystemChecks = false;
   bool ranOSCheck = false;
   Json::Value customContent;
+  Json::Value configureSnippetData;
+  std::string configureSnippetName;
 #ifndef CMAKE_BOOTSTRAP
   std::unique_ptr<cmsys::SystemInformation> systemInformation;
   cmsys::SystemInformation& GetSystemInformation();

+ 0 - 1
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -1055,7 +1055,6 @@ 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;
         std::vector<std::string> const& outputs = ccg.GetOutputs();
         for (size_t i = 0; i < outputs.size(); ++i) {

+ 0 - 2
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -545,8 +545,6 @@ 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();

+ 0 - 2
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -792,8 +792,6 @@ 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();

+ 0 - 2
Source/cmMakefileTargetGenerator.cxx

@@ -932,7 +932,6 @@ 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();
@@ -1713,7 +1712,6 @@ 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();

+ 0 - 9
Source/cmNinjaNormalTargetGenerator.cxx

@@ -294,9 +294,6 @@ 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 =
       this->GetGeneratorTarget()->GetLinkerTool("CUDA", config);
@@ -404,9 +401,6 @@ 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";
   vars.Fatbinary = "$FATBIN";
@@ -466,9 +460,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(
     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();
     std::string lang = this->TargetLinkLanguage(config);

+ 0 - 3
Source/cmNinjaTargetGenerator.cxx

@@ -596,7 +596,6 @@ 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();
@@ -656,8 +655,6 @@ void cmNinjaTargetGenerator::WriteCompileRule(std::string const& 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";

+ 0 - 7
Source/cmRulePlaceholderExpander.cxx

@@ -266,13 +266,6 @@ 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;

+ 0 - 1
Source/cmRulePlaceholderExpander.h

@@ -32,7 +32,6 @@ public:
   {
     char const* CMTargetName = nullptr;
     char const* CMTargetType = nullptr;
-    char const* CMTargetLabels = nullptr;
     char const* TargetPDB = nullptr;
     char const* TargetCompilePDB = nullptr;
     char const* TargetVersionMajor = nullptr;

+ 4 - 2
Source/cmake.cxx

@@ -2761,8 +2761,7 @@ int cmake::ActualConfigure()
       "RULE_LAUNCH_LINK",
       cmStrCat(
         launcher, "--command-type link", common_args,
-        "--output <TARGET> --target-type <TARGET_TYPE> "
-        "--language <LANGUAGE> --target-labels \"<TARGET_LABELS>\" -- "));
+        "--output <TARGET> --config <CONFIG> --language <LANGUAGE> -- "));
     this->State->SetGlobalProperty(
       "RULE_LAUNCH_CUSTOM",
       cmStrCat(launcher, "--command-type custom", common_args,
@@ -3116,6 +3115,9 @@ int cmake::Generate()
       return -1;
     }
     this->GlobalGenerator->Generate();
+    if (this->Instrumentation->HasQuery()) {
+      this->Instrumentation->WriteCMakeContent(this->GlobalGenerator);
+    }
     return 0;
   };
 

+ 25 - 11
Tests/RunCMake/Instrumentation/check-custom-content.cmake

@@ -10,25 +10,39 @@ if (NOT ${num} EQUAL 2)
   add_error("Found ${num} custom content files, expected 2.")
 endif()
 
-# Check contents of configureContent files
+# Check contents of cmakeContent files
 set(firstFile "")
 foreach(content_file IN LISTS content_files)
   read_json("${content_file}" contents)
-  json_assert_key("${content_file}" "${contents}" myString "string")
-  json_assert_key("${content_file}" "${contents}" myBool "OFF")
-  json_assert_key("${content_file}" "${contents}" myInt "1")
-  json_assert_key("${content_file}" "${contents}" myFloat "2.5")
-  json_assert_key("${content_file}" "${contents}" myTrue "ON")
-  json_assert_key("${content_file}" "${contents}" myList "[ \"a\", \"b\", \"c\" ]")
-  json_assert_key("${content_file}" "${contents}" myObject "{.*\"key\".*:.*\"value\".*}")
+
+  # Check custom content
+  string(JSON custom GET "${contents}" custom)
+  json_assert_key("${content_file}" "${custom}" myString "string")
+  json_assert_key("${content_file}" "${custom}" myBool "OFF")
+  json_assert_key("${content_file}" "${custom}" myInt "1")
+  json_assert_key("${content_file}" "${custom}" myFloat "2.5")
+  json_assert_key("${content_file}" "${custom}" myTrue "ON")
+  json_assert_key("${content_file}" "${custom}" myList "\\[ \"a\", \"b\", \"c\" \\]")
+  json_assert_key("${content_file}" "${custom}" myObject "{.*\"key\".*:.*\"value\".*}")
   if (NOT firstFile)
     set(firstFile "${content_file}")
   endif()
   if ("${content_file}" STREQUAL "${firstFile}")
-    string(JSON firstN GET "${contents}" nConfigure)
+    string(JSON firstN GET "${custom}" nConfigure)
   else()
-    string(JSON secondN GET "${contents}" nConfigure)
+    string(JSON secondN GET "${custom}" nConfigure)
   endif()
+
+  # Check target content
+  string(JSON targets GET "${contents}" targets)
+  string(JSON targetData GET "${targets}" lib)
+  json_assert_key("${content_file}" "${targetData}" labels "\\[ \"label3\" \\]")
+  json_assert_key("${content_file}" "${targetData}" type "STATIC_LIBRARY")
+
+  string(JSON targetData GET "${targets}" main)
+  json_assert_key("${content_file}" "${targetData}" labels "\\[ \"label1\", \"label2\" \\]")
+  json_assert_key("${content_file}" "${targetData}" type "EXECUTABLE")
+
 endforeach()
 
 # Ensure provided -DN=* arguments result in differing JSON contents
@@ -40,7 +54,7 @@ endif()
 # Ensure snippets reference valid files
 foreach(snippet IN LISTS snippets)
   read_json("${snippet}" contents)
-  string(JSON filename GET "${contents}" configureContent)
+  string(JSON filename GET "${contents}" cmakeContent)
   if (NOT EXISTS "${v1}/data/${filename}")
     add_error("Reference to content file that does not exist.")
   endif()

+ 2 - 30
Tests/RunCMake/Instrumentation/check-data-dir.cmake

@@ -51,36 +51,8 @@ foreach(snippet IN LISTS snippets)
   # Verify contents of link-* Snippets
   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")
-        json_error("${snippet}" "Expected EXECUTABLE, target type was ${targetType}")
-      endif()
-      string(JSON nlabels LENGTH "${targetLabels}")
-      if (NOT nlabels STREQUAL 2)
-        json_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")
-          json_error("${snippet}" "Missing Target Labels for: ${target}")
-        endif()
-      endif()
-    endif()
-    if (target MATCHES "lib")
-      if (NOT targetType MATCHES "STATIC_LIBRARY")
-        json_error("${snippet}" "Expected STATIC_LIBRARY, target type was ${targetType}")
-      endif()
-      string(JSON nlabels LENGTH "${targetLabels}")
-      if (NOT nlabels STREQUAL 1)
-        json_error("${snippet}" "Missing Target Labels for: ${target}")
-      else()
-        string(JSON label ERROR_VARIABLE noLabels GET "${contents}" targetLabels 0)
-        if (NOT label MATCHES "label3")
-          json_error("${snippet}" "Missing Target Labels for: ${target}")
-        endif()
-      endif()
+    if (NOT target MATCHES "main|lib")
+      json_error("${snippet}" "Unexpected link target: ${target}")
     endif()
   endif()
 

+ 0 - 2
Tests/RunCMake/Instrumentation/verify-snippet.cmake

@@ -14,8 +14,6 @@ function(snippet_has_fields snippet contents)
     json_has_key("${snippet}" "${contents}" target)
     json_has_key("${snippet}" "${contents}" outputs)
     json_has_key("${snippet}" "${contents}" outputSizes)
-    json_has_key("${snippet}" "${contents}" targetType)
-    json_has_key("${snippet}" "${contents}" targetLabels)
     json_has_key("${snippet}" "${contents}" config)
     json_has_key("${snippet}" "${contents}" language)
   elseif (filename MATCHES "^compile-*")