From ea430582f96a085e1b4d7c5125d5ca8a2266e48b Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 5 Mar 2021 11:40:22 -0500
Subject: cmInstallTargetGenerator: Drop unused GetNamelinkMode method

---
 Source/cmInstallTargetGenerator.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index 8c5d444..b94c2a6 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -39,7 +39,6 @@ public:
     NamelinkModeSkip
   };
   void SetNamelinkMode(NamelinkModeType mode) { this->NamelinkMode = mode; }
-  NamelinkModeType GetNamelinkMode() const { return this->NamelinkMode; }
 
   std::string GetInstallFilename(const std::string& config) const;
 
-- 
cgit v0.12


From f73b6879e9f93157bc3bec26ee319cf67e6b026a Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 5 Mar 2021 11:41:06 -0500
Subject: cmInstallTargetGenerator: Report namelink mode with list of files

---
 Source/cmInstallTargetGenerator.cxx | 1 +
 Source/cmInstallTargetGenerator.h   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index bef785d..eb214fa 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -338,6 +338,7 @@ cmInstallTargetGenerator::Files cmInstallTargetGenerator::GetFiles(
 
       // Add the names based on the current namelink mode.
       if (haveNamelink) {
+        files.NamelinkMode = this->NamelinkMode;
         // With a namelink we need to check the mode.
         if (this->NamelinkMode == NamelinkModeOnly) {
           // Install the namelink only.
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index b94c2a6..84fce42 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -81,6 +81,7 @@ public:
     // Prefix for all files in To.
     std::string ToDir;
 
+    NamelinkModeType NamelinkMode = NamelinkModeNone;
     bool NoTweak = false;
     bool UseSourcePermissions = false;
     cmInstallType Type = cmInstallType();
-- 
cgit v0.12


From 415ead81533ead72fca8a495c3cbc17e2bf4e400 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 11 Jan 2021 10:19:38 -0500
Subject: cmFileAPICodemodel: Build map from each target to its index

---
 Source/cmFileAPICodemodel.cxx | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 9061109..596edd1 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -46,6 +46,9 @@
 
 namespace {
 
+using TargetIndexMapType =
+  std::unordered_map<cmGeneratorTarget const*, Json::ArrayIndex>;
+
 class Codemodel
 {
   cmFileAPI& FileAPI;
@@ -94,6 +97,8 @@ class CodemodelConfig
     ProjectMap;
   std::vector<Project> Projects;
 
+  TargetIndexMapType TargetIndexMap;
+
   void ProcessDirectories();
 
   Json::ArrayIndex GetDirectoryIndex(cmLocalGenerator const* lg);
@@ -663,6 +668,8 @@ Json::Value CodemodelConfig::DumpTarget(cmGeneratorTarget* gt,
   target["projectIndex"] = pi;
   this->Projects[pi].TargetIndexes.append(ti);
 
+  this->TargetIndexMap[gt] = ti;
+
   return target;
 }
 
-- 
cgit v0.12


From fd30bd93e6f4334a9cd317a1e5eb8181fffa7a42 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 11 Jan 2021 09:17:05 -0500
Subject: fileapi: Re-organize backtrace infrastructure

Make it available to more parts of the codemodel object.
---
 Help/manual/cmake-file-api.7.rst             |  76 ++++++------
 Source/cmFileAPICodemodel.cxx                | 168 +++++++++++++--------------
 Tests/RunCMake/FileAPI/codemodel-v2-check.py |   5 +-
 3 files changed, 128 insertions(+), 121 deletions(-)

diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 89739b7..133282d 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -964,40 +964,48 @@ with members:
       with forward slashes.
 
 ``backtraceGraph``
-  A JSON object describing the graph of backtraces whose nodes are
-  referenced from ``backtrace`` members elsewhere.  The members are:
-
-  ``nodes``
-    A JSON array listing nodes in the backtrace graph.  Each entry
-    is a JSON object with members:
-
-    ``file``
-      An unsigned integer 0-based index into the backtrace ``files`` array.
-
-    ``line``
-      An optional member present when the node represents a line within
-      the file.  The value is an unsigned integer 1-based line number.
-
-    ``command``
-      An optional member present when the node represents a command
-      invocation within the file.  The value is an unsigned integer
-      0-based index into the backtrace ``commands`` array.
-
-    ``parent``
-      An optional member present when the node is not the bottom of
-      the call stack.  The value is an unsigned integer 0-based index
-      of another entry in the backtrace ``nodes`` array.
-
-  ``commands``
-    A JSON array listing command names referenced by backtrace nodes.
-    Each entry is a string specifying a command name.
-
-  ``files``
-    A JSON array listing CMake language files referenced by backtrace nodes.
-    Each entry is a string specifying the path to a file, represented
-    with forward slashes.  If the file is inside the top-level source
-    directory then the path is specified relative to that directory.
-    Otherwise the path is absolute.
+  A `"codemodel" version 2 "backtrace graph"`_ whose nodes are referenced
+  from ``backtrace`` members elsewhere in this "target" object.
+
+"codemodel" version 2 "backtrace graph"
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``backtraceGraph`` member of a `"codemodel" version 2 "target" object`_
+is a JSON object describing a graph of backtraces.  Its nodes are referenced
+from ``backtrace`` members elsewhere in the containing object.
+The backtrace graph object members are:
+
+``nodes``
+  A JSON array listing nodes in the backtrace graph.  Each entry
+  is a JSON object with members:
+
+  ``file``
+    An unsigned integer 0-based index into the backtrace ``files`` array.
+
+  ``line``
+    An optional member present when the node represents a line within
+    the file.  The value is an unsigned integer 1-based line number.
+
+  ``command``
+    An optional member present when the node represents a command
+    invocation within the file.  The value is an unsigned integer
+    0-based index into the backtrace ``commands`` array.
+
+  ``parent``
+    An optional member present when the node is not the bottom of
+    the call stack.  The value is an unsigned integer 0-based index
+    of another entry in the backtrace ``nodes`` array.
+
+``commands``
+  A JSON array listing command names referenced by backtrace nodes.
+  Each entry is a string specifying a command name.
+
+``files``
+  A JSON array listing CMake language files referenced by backtrace nodes.
+  Each entry is a string specifying the path to a file, represented
+  with forward slashes.  If the file is inside the top-level source
+  directory then the path is specified relative to that directory.
+  Otherwise the path is absolute.
 
 Object Kind "cache"
 -------------------
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 596edd1..ed6ac8e 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -49,80 +49,6 @@ namespace {
 using TargetIndexMapType =
   std::unordered_map<cmGeneratorTarget const*, Json::ArrayIndex>;
 
-class Codemodel
-{
-  cmFileAPI& FileAPI;
-  unsigned long Version;
-
-  Json::Value DumpPaths();
-  Json::Value DumpConfigurations();
-  Json::Value DumpConfiguration(std::string const& config);
-
-public:
-  Codemodel(cmFileAPI& fileAPI, unsigned long version);
-  Json::Value Dump();
-};
-
-class CodemodelConfig
-{
-  cmFileAPI& FileAPI;
-  unsigned long Version;
-  std::string const& Config;
-  std::string TopSource;
-  std::string TopBuild;
-
-  struct Directory
-  {
-    cmStateSnapshot Snapshot;
-    cmLocalGenerator const* LocalGenerator = nullptr;
-    Json::Value TargetIndexes = Json::arrayValue;
-    Json::ArrayIndex ProjectIndex;
-    bool HasInstallRule = false;
-  };
-  std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
-    DirectoryMap;
-  std::vector<Directory> Directories;
-
-  struct Project
-  {
-    cmStateSnapshot Snapshot;
-    static const Json::ArrayIndex NoParentIndex =
-      static_cast<Json::ArrayIndex>(-1);
-    Json::ArrayIndex ParentIndex = NoParentIndex;
-    Json::Value ChildIndexes = Json::arrayValue;
-    Json::Value DirectoryIndexes = Json::arrayValue;
-    Json::Value TargetIndexes = Json::arrayValue;
-  };
-  std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
-    ProjectMap;
-  std::vector<Project> Projects;
-
-  TargetIndexMapType TargetIndexMap;
-
-  void ProcessDirectories();
-
-  Json::ArrayIndex GetDirectoryIndex(cmLocalGenerator const* lg);
-  Json::ArrayIndex GetDirectoryIndex(cmStateSnapshot s);
-
-  Json::ArrayIndex AddProject(cmStateSnapshot s);
-
-  Json::Value DumpTargets();
-  Json::Value DumpTarget(cmGeneratorTarget* gt, Json::ArrayIndex ti);
-
-  Json::Value DumpDirectories();
-  Json::Value DumpDirectory(Directory& d);
-
-  Json::Value DumpProjects();
-  Json::Value DumpProject(Project& p);
-
-  Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s);
-
-public:
-  CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
-                  std::string const& config);
-  Json::Value Dump();
-};
-
 std::string RelativeIfUnder(std::string const& top, std::string const& in)
 {
   std::string out;
@@ -136,16 +62,6 @@ std::string RelativeIfUnder(std::string const& top, std::string const& in)
   return out;
 }
 
-std::string TargetId(cmGeneratorTarget const* gt, std::string const& topBuild)
-{
-  cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_256);
-  std::string path = RelativeIfUnder(
-    topBuild, gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
-  std::string hash = hasher.HashString(path);
-  hash.resize(20, '0');
-  return gt->GetName() + CMAKE_DIRECTORY_ID_SEP + hash;
-}
-
 class JBTIndex
 {
 public:
@@ -295,6 +211,90 @@ Json::Value BacktraceData::Dump()
   return backtraceGraph;
 }
 
+class Codemodel
+{
+  cmFileAPI& FileAPI;
+  unsigned long Version;
+
+  Json::Value DumpPaths();
+  Json::Value DumpConfigurations();
+  Json::Value DumpConfiguration(std::string const& config);
+
+public:
+  Codemodel(cmFileAPI& fileAPI, unsigned long version);
+  Json::Value Dump();
+};
+
+class CodemodelConfig
+{
+  cmFileAPI& FileAPI;
+  unsigned long Version;
+  std::string const& Config;
+  std::string TopSource;
+  std::string TopBuild;
+
+  struct Directory
+  {
+    cmStateSnapshot Snapshot;
+    cmLocalGenerator const* LocalGenerator = nullptr;
+    Json::Value TargetIndexes = Json::arrayValue;
+    Json::ArrayIndex ProjectIndex;
+    bool HasInstallRule = false;
+  };
+  std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
+    DirectoryMap;
+  std::vector<Directory> Directories;
+
+  struct Project
+  {
+    cmStateSnapshot Snapshot;
+    static const Json::ArrayIndex NoParentIndex =
+      static_cast<Json::ArrayIndex>(-1);
+    Json::ArrayIndex ParentIndex = NoParentIndex;
+    Json::Value ChildIndexes = Json::arrayValue;
+    Json::Value DirectoryIndexes = Json::arrayValue;
+    Json::Value TargetIndexes = Json::arrayValue;
+  };
+  std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
+    ProjectMap;
+  std::vector<Project> Projects;
+
+  TargetIndexMapType TargetIndexMap;
+
+  void ProcessDirectories();
+
+  Json::ArrayIndex GetDirectoryIndex(cmLocalGenerator const* lg);
+  Json::ArrayIndex GetDirectoryIndex(cmStateSnapshot s);
+
+  Json::ArrayIndex AddProject(cmStateSnapshot s);
+
+  Json::Value DumpTargets();
+  Json::Value DumpTarget(cmGeneratorTarget* gt, Json::ArrayIndex ti);
+
+  Json::Value DumpDirectories();
+  Json::Value DumpDirectory(Directory& d);
+
+  Json::Value DumpProjects();
+  Json::Value DumpProject(Project& p);
+
+  Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s);
+
+public:
+  CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
+                  std::string const& config);
+  Json::Value Dump();
+};
+
+std::string TargetId(cmGeneratorTarget const* gt, std::string const& topBuild)
+{
+  cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_256);
+  std::string path = RelativeIfUnder(
+    topBuild, gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
+  std::string hash = hasher.HashString(path);
+  hash.resize(20, '0');
+  return gt->GetName() + CMAKE_DIRECTORY_ID_SEP + hash;
+}
+
 struct CompileData
 {
   struct IncludeEntry
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
index df2410a..e155037 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
@@ -94,8 +94,7 @@ def check_directory(c):
 
     return _check
 
-def check_target_backtrace_graph(t):
-    btg = t["backtraceGraph"]
+def check_backtrace_graph(btg):
     assert is_dict(btg)
     assert sorted(btg.keys()) == ["commands", "files", "nodes"]
     assert is_list(btg["commands"])
@@ -148,7 +147,7 @@ def check_target(c):
         assert is_string(obj["name"], expected["name"])
         assert matches(obj["id"], expected["id"])
         assert is_string(obj["type"], expected["type"])
-        check_target_backtrace_graph(obj)
+        check_backtrace_graph(obj["backtraceGraph"])
 
         assert is_dict(obj["paths"])
         assert sorted(obj["paths"].keys()) == ["build", "source"]
-- 
cgit v0.12


From a12d7f70b1b97f74293d9861a1827c88ef46ec39 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Thu, 14 Jan 2021 15:10:49 -0500
Subject: fileapi: Add a "directory" object to codemodel-v2

This object will contain more detailed directory-level information.

Co-Authored-by: Kyle Edwards <kyle.edwards@kitware.com>
---
 Help/manual/cmake-file-api.7.rst                   |  37 +++++++-
 Help/release/dev/fileapi-codemodel-directory.rst   |   8 ++
 Source/cmFileAPI.cxx                               |   2 +-
 Source/cmFileAPICodemodel.cxx                      |  72 ++++++++++++++-
 .../RunCMake/CommandLine/E_capabilities-stdout.txt |   2 +-
 .../codemodel-v2-ClientStateful-check.cmake        |   1 +
 .../codemodel-v2-ClientStateless-check.cmake       |   1 +
 .../codemodel-v2-SharedStateless-check.cmake       |   1 +
 Tests/RunCMake/FileAPI/codemodel-v2-check.py       |  22 ++++-
 .../codemodel-v2-data/directories/external.json    |   2 +-
 .../codemodel-v2-data/targets/c_shared_lib.json    | 101 ++++++++++++++++++++-
 .../codemodel-v2-data/targets/cxx_shared_lib.json  |  95 ++++++++++++++++++-
 Tests/RunCMake/FileAPI/codemodel-v2.cmake          |  17 +++-
 Tests/RunCMake/FileAPI/cxx/CMakeLists.txt          |   2 +-
 .../RunCMake/FileAPIExternalSource/CMakeLists.txt  |   3 +
 15 files changed, 351 insertions(+), 15 deletions(-)
 create mode 100644 Help/release/dev/fileapi-codemodel-directory.rst

diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 133282d..7c34d51 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -443,7 +443,8 @@ Version 1 does not exist to avoid confusion with that from
             "hasInstallRule": true,
             "minimumCMakeVersion": {
               "string": "3.14"
-            }
+            },
+            "jsonFile": "<file>"
           },
           {
             "source": "sub",
@@ -453,7 +454,8 @@ Version 1 does not exist to avoid confusion with that from
             "targetIndexes": [ 1 ],
             "minimumCMakeVersion": {
               "string": "3.14"
-            }
+            },
+            "jsonFile": "<file>"
           }
         ],
         "projects": [
@@ -569,6 +571,13 @@ The members specific to ``codemodel`` objects are:
       :command:`install` rules, i.e. whether a ``make install``
       or equivalent rule is available.
 
+    ``jsonFile``
+      A JSON string specifying a path relative to the codemodel file
+      to another JSON file containing a
+      `"codemodel" version 2 "directory" object`_.
+
+      This field was added in codemodel version 2.3.
+
   ``projects``
     A JSON array of entries corresponding to the top-level project
     and sub-projects defined in the build system.  Each (sub-)project
@@ -633,6 +642,30 @@ The members specific to ``codemodel`` objects are:
       to another JSON file containing a
       `"codemodel" version 2 "target" object`_.
 
+"codemodel" version 2 "directory" object
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A codemodel "directory" object is referenced by a `"codemodel" version 2`_
+object's ``directories`` array.  Each "directory" object is a JSON object
+with members:
+
+``paths``
+  A JSON object containing members:
+
+  ``source``
+    A string specifying the path to the source directory, represented
+    with forward slashes.  If the directory is inside the top-level
+    source directory then the path is specified relative to that
+    directory (with ``.`` for the top-level source directory itself).
+    Otherwise the path is absolute.
+
+  ``build``
+    A string specifying the path to the build directory, represented
+    with forward slashes.  If the directory is inside the top-level
+    build directory then the path is specified relative to that
+    directory (with ``.`` for the top-level build directory itself).
+    Otherwise the path is absolute.
+
 "codemodel" version 2 "target" object
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/Help/release/dev/fileapi-codemodel-directory.rst b/Help/release/dev/fileapi-codemodel-directory.rst
new file mode 100644
index 0000000..7dffb96
--- /dev/null
+++ b/Help/release/dev/fileapi-codemodel-directory.rst
@@ -0,0 +1,8 @@
+fileapi-codemodel-directory
+---------------------------
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 ``version`` field has
+  component been updated to 2.3.
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 gained a
+  new "directory" object containing directory-level information.
diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx
index d2a9bec..d529f52 100644
--- a/Source/cmFileAPI.cxx
+++ b/Source/cmFileAPI.cxx
@@ -686,7 +686,7 @@ std::string cmFileAPI::NoSupportedVersion(
 
 // The "codemodel" object kind.
 
-static unsigned int const CodeModelV2Minor = 2;
+static unsigned int const CodeModelV2Minor = 3;
 
 void cmFileAPI::BuildClientRequestCodeModel(
   ClientRequest& r, std::vector<RequestVersion> const& versions)
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index ed6ac8e..2f36db2 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -273,6 +273,7 @@ class CodemodelConfig
 
   Json::Value DumpDirectories();
   Json::Value DumpDirectory(Directory& d);
+  Json::Value DumpDirectoryObject(Directory& d);
 
   Json::Value DumpProjects();
   Json::Value DumpProject(Project& p);
@@ -372,6 +373,20 @@ struct hash<CompileData>
 } // namespace std
 
 namespace {
+class DirectoryObject
+{
+  cmLocalGenerator const* LG = nullptr;
+  std::string const& Config;
+  std::string TopSource;
+  std::string TopBuild;
+
+  Json::Value DumpPaths();
+
+public:
+  DirectoryObject(cmLocalGenerator const* lg, std::string const& config);
+  Json::Value Dump();
+};
+
 class Target
 {
   cmGeneratorTarget* GT;
@@ -684,7 +699,7 @@ Json::Value CodemodelConfig::DumpDirectories()
 
 Json::Value CodemodelConfig::DumpDirectory(Directory& d)
 {
-  Json::Value directory = Json::objectValue;
+  Json::Value directory = this->DumpDirectoryObject(d);
 
   std::string sourceDir = d.Snapshot.GetDirectory().GetCurrentSource();
   directory["source"] = RelativeIfUnder(this->TopSource, sourceDir);
@@ -724,6 +739,31 @@ Json::Value CodemodelConfig::DumpDirectory(Directory& d)
   return directory;
 }
 
+Json::Value CodemodelConfig::DumpDirectoryObject(Directory& d)
+{
+  std::string prefix = "directory";
+  std::string sourceDirRel = RelativeIfUnder(
+    this->TopSource, d.Snapshot.GetDirectory().GetCurrentSource());
+  std::string buildDirRel = RelativeIfUnder(
+    this->TopBuild, d.Snapshot.GetDirectory().GetCurrentBinary());
+  if (!cmSystemTools::FileIsFullPath(buildDirRel)) {
+    prefix = cmStrCat(prefix, '-', buildDirRel);
+  } else if (!cmSystemTools::FileIsFullPath(sourceDirRel)) {
+    prefix = cmStrCat(prefix, '-', sourceDirRel);
+  }
+  for (char& c : prefix) {
+    if (c == '/' || c == '\\') {
+      c = '.';
+    }
+  }
+  if (!this->Config.empty()) {
+    prefix += "-" + this->Config;
+  }
+
+  DirectoryObject dir(d.LocalGenerator, this->Config);
+  return this->FileAPI.MaybeJsonFile(dir.Dump(), prefix);
+}
+
 Json::Value CodemodelConfig::DumpProjects()
 {
   Json::Value projects = Json::arrayValue;
@@ -767,6 +807,36 @@ Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s)
   return minimumCMakeVersion;
 }
 
+DirectoryObject::DirectoryObject(cmLocalGenerator const* lg,
+                                 std::string const& config)
+  : LG(lg)
+  , Config(config)
+  , TopSource(lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
+  , TopBuild(
+      lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
+{
+}
+
+Json::Value DirectoryObject::Dump()
+{
+  Json::Value directoryObject = Json::objectValue;
+  directoryObject["paths"] = this->DumpPaths();
+  return directoryObject;
+}
+
+Json::Value DirectoryObject::DumpPaths()
+{
+  Json::Value paths = Json::objectValue;
+
+  std::string const& sourceDir = this->LG->GetCurrentSourceDirectory();
+  paths["source"] = RelativeIfUnder(this->TopSource, sourceDir);
+
+  std::string const& buildDir = this->LG->GetCurrentBinaryDirectory();
+  paths["build"] = RelativeIfUnder(this->TopBuild, buildDir);
+
+  return paths;
+}
+
 Target::Target(cmGeneratorTarget* gt, std::string const& config)
   : GT(gt)
   , Config(config)
diff --git a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
index c76c92d..3df3e52 100644
--- a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
+++ b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
@@ -1 +1 @@
-^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":2}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"version":{.*}}$
+^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":3}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"version":{.*}}$
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake
index fb78e87..91cdf7c 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake
@@ -4,6 +4,7 @@ set(expect
   query/client-foo/query.json
   reply
   reply/codemodel-v2-[0-9a-f]+\\.json
+  .*
   reply/index-[0-9.T-]+\\.json
   .*
   )
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateless-check.cmake b/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateless-check.cmake
index 7c6a35a..9aa9e4a 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateless-check.cmake
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateless-check.cmake
@@ -4,6 +4,7 @@ set(expect
   query/client-foo/codemodel-v2
   reply
   reply/codemodel-v2-[0-9a-f]+\\.json
+  .*
   reply/index-[0-9.T-]+\\.json
   .*
   )
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-SharedStateless-check.cmake b/Tests/RunCMake/FileAPI/codemodel-v2-SharedStateless-check.cmake
index cc2f31b..43d1a0b 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-SharedStateless-check.cmake
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-SharedStateless-check.cmake
@@ -3,6 +3,7 @@ set(expect
   query/codemodel-v2
   reply
   reply/codemodel-v2-[0-9a-f]+\\.json
+  .*
   reply/index-[0-9.T-]+\\.json
   .*
   )
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
index e155037..0e5b3b9 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
@@ -12,7 +12,7 @@ def read_codemodel_json_data(filename):
 def check_objects(o, g):
     assert is_list(o)
     assert len(o) == 1
-    check_index_object(o[0], "codemodel", 2, 2, check_object_codemodel(g))
+    check_index_object(o[0], "codemodel", 2, 3, check_object_codemodel(g))
 
 def check_backtrace(t, b, backtrace):
     btg = t["backtraceGraph"]
@@ -55,7 +55,7 @@ def check_backtraces(t, actual, expected):
 def check_directory(c):
     def _check(actual, expected):
         assert is_dict(actual)
-        expected_keys = ["build", "source", "projectIndex"]
+        expected_keys = ["build", "jsonFile", "source", "projectIndex"]
         assert matches(actual["build"], expected["build"])
 
         assert is_int(actual["projectIndex"])
@@ -92,6 +92,17 @@ def check_directory(c):
 
         assert sorted(actual.keys()) == sorted(expected_keys)
 
+        assert is_string(actual["jsonFile"])
+        filepath = os.path.join(reply_dir, actual["jsonFile"])
+        with open(filepath) as f:
+            d = json.load(f)
+
+        assert is_dict(d)
+        assert sorted(d.keys()) == ["paths"]
+
+        assert is_string(d["paths"]["source"], actual["source"])
+        assert is_string(d["paths"]["build"], actual["build"])
+
     return _check
 
 def check_backtrace_graph(btg):
@@ -704,6 +715,13 @@ def gen_check_targets(c, g, inSource):
     if sys.platform not in ("win32", "cygwin", "msys"):
         for e in expected:
             e["artifacts"] = filter_list(lambda a: not a["_dllExtra"], e["artifacts"])
+            if e["install"] is not None:
+                e["install"]["destinations"] = filter_list(lambda d: "_dllExtra" not in d or not d["_dllExtra"], e["install"]["destinations"])
+
+    else:
+        for e in expected:
+            if e["install"] is not None:
+                e["install"]["destinations"] = filter_list(lambda d: "_namelink" not in d or not d["_namelink"], e["install"]["destinations"])
 
     if "aix" not in sys.platform:
         for e in expected:
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json
index 521e3c7..0d3161c 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json
@@ -10,5 +10,5 @@
     ],
     "projectName": "External",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": true
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
index 176a857..5588bd5 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
@@ -90,10 +90,10 @@
         }
     ],
     "folder": null,
-    "nameOnDisk": "^(lib|cyg)?c_shared_lib\\.(so|dylib|dll)$",
+    "nameOnDisk": "^(lib|cyg)?c_shared_lib(-1)?\\.(so|dylib|dll)$",
     "artifacts": [
         {
-            "path": "^lib/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?(lib|cyg)?c_shared_lib\\.(so|dylib|dll)$",
+            "path": "^lib/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?(lib|cyg)?c_shared_lib(-1)?\\.(so|dylib|dll)$",
             "_dllExtra": false
         },
         {
@@ -101,13 +101,106 @@
             "_dllExtra": true
         },
         {
-            "path": "^lib/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?(lib|cyg)?c_shared_lib\\.pdb$",
+            "path": "^lib/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?(lib|cyg)?c_shared_lib(-1)?\\.pdb$",
             "_dllExtra": true
         }
     ],
     "build": "^\\.$",
     "source": "^\\.$",
-    "install": null,
+    "install": {
+        "prefix": "^(/usr/local|[A-Za-z]:.*/codemodel-v2)$",
+        "destinations": [
+            {
+                "path": "lib",
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 41,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            },
+            {
+                "path": "lib",
+                "_dllExtra": true,
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 41,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            },
+            {
+                "path": "lib",
+                "_namelink": true,
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 46,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            }
+        ]
+    },
     "link": {
         "language": "C",
         "lto": true,
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
index 171a4f5..e5e1d0d 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
@@ -83,7 +83,100 @@
     ],
     "build": "^cxx$",
     "source": "^cxx$",
-    "install": null,
+    "install": {
+        "prefix": "^(/usr/local|[A-Za-z]:.*/codemodel-v2)$",
+        "destinations": [
+            {
+                "path": "lib",
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 41,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            },
+            {
+                "path": "lib",
+                "_dllExtra": true,
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 41,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            },
+            {
+                "path": "lib",
+                "_namelink": true,
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 46,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            }
+        ]
+    },
     "link": {
         "language": "CXX",
         "lto": null,
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2.cmake b/Tests/RunCMake/FileAPI/codemodel-v2.cmake
index 2405954..528f075 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2.cmake
+++ b/Tests/RunCMake/FileAPI/codemodel-v2.cmake
@@ -35,4 +35,19 @@ if(_ipo)
   file(WRITE "${CMAKE_BINARY_DIR}/ipo_enabled.txt" "")
 endif()
 
-install(TARGETS cxx_exe)
+install(TARGETS cxx_exe COMPONENT Tools EXPORT FooTargets)
+
+set_target_properties(c_shared_lib PROPERTIES VERSION 1.2.3 SOVERSION 1)
+install(TARGETS c_shared_lib cxx_shared_lib
+  ARCHIVE DESTINATION lib
+  RUNTIME DESTINATION lib
+  LIBRARY DESTINATION lib NAMELINK_SKIP
+  )
+install(TARGETS c_shared_lib cxx_shared_lib LIBRARY NAMELINK_ONLY)
+
+install(FILES empty.h TYPE INCLUDE RENAME empty-renamed.h OPTIONAL)
+install(FILES codemodel-v2.cmake empty.h DESTINATION include)
+install(DIRECTORY . dir cxx/ OPTIONAL DESTINATION dir1)
+install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/dir" "${CMAKE_CURRENT_SOURCE_DIR}/cxx/" DESTINATION dir2)
+install(EXPORT FooTargets DESTINATION lib/cmake/foo)
+install(SCRIPT InstallScript.cmake)
diff --git a/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt b/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
index 76235f5..95c803f 100644
--- a/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
+++ b/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
@@ -16,7 +16,7 @@ target_link_libraries(cxx_static_exe PRIVATE cxx_static_lib)
 
 target_compile_options(cxx_exe PUBLIC TargetCompileOptions)
 target_link_options(cxx_exe PUBLIC TargetLinkOptions)
-target_link_directories(cxx_exe PUBLIC "${CMAKE_BINARY_DIR}/TargetLinkDir")
+target_link_directories(cxx_exe PUBLIC "$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/TargetLinkDir>")
 
 target_precompile_headers(cxx_exe PUBLIC ../empty.h)
 
diff --git a/Tests/RunCMake/FileAPIExternalSource/CMakeLists.txt b/Tests/RunCMake/FileAPIExternalSource/CMakeLists.txt
index b3ca660..2865864 100644
--- a/Tests/RunCMake/FileAPIExternalSource/CMakeLists.txt
+++ b/Tests/RunCMake/FileAPIExternalSource/CMakeLists.txt
@@ -11,3 +11,6 @@ set_property(SOURCE empty.c PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY
 target_include_directories(generated_exe SYSTEM PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
 target_compile_definitions(generated_exe PRIVATE GENERATED_EXE=1 -DTGT_DUMMY)
 set_source_files_properties(empty.c PROPERTIES COMPILE_OPTIONS SRC_COMPILE_OPTIONS_DUMMY)
+
+install(DIRECTORY . DESTINATION dir3)
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} EXCLUDE_FROM_ALL DESTINATION dir4)
-- 
cgit v0.12


From eae2256a529250e4fda639a79a9edddef6604f12 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Thu, 14 Jan 2021 16:17:56 -0500
Subject: fileapi: Add backtraceGraph to codemodel-v2 "directory" object

Co-Authored-by: Kyle Edwards <kyle.edwards@kitware.com>
---
 Help/manual/cmake-file-api.7.rst             | 12 ++++++++----
 Source/cmFileAPICodemodel.cxx                | 13 +++++++++++++
 Tests/RunCMake/FileAPI/codemodel-v2-check.py |  4 +++-
 3 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 7c34d51..088ec2e 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -666,6 +666,10 @@ with members:
     directory (with ``.`` for the top-level build directory itself).
     Otherwise the path is absolute.
 
+``backtraceGraph``
+  A `"codemodel" version 2 "backtrace graph"`_ whose nodes are referenced
+  from ``backtrace`` members elsewhere in this "directory" object.
+
 "codemodel" version 2 "target" object
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -1003,10 +1007,10 @@ with members:
 "codemodel" version 2 "backtrace graph"
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-The ``backtraceGraph`` member of a `"codemodel" version 2 "target" object`_
-is a JSON object describing a graph of backtraces.  Its nodes are referenced
-from ``backtrace`` members elsewhere in the containing object.
-The backtrace graph object members are:
+The ``backtraceGraph`` member of a `"codemodel" version 2 "directory" object`_,
+or `"codemodel" version 2 "target" object`_ is a JSON object describing a
+graph of backtraces.  Its nodes are referenced from ``backtrace`` members
+elsewhere in the containing object.  The backtrace graph object members are:
 
 ``nodes``
   A JSON array listing nodes in the backtrace graph.  Each entry
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 2f36db2..e7bfc61 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -379,6 +379,9 @@ class DirectoryObject
   std::string const& Config;
   std::string TopSource;
   std::string TopBuild;
+  BacktraceData Backtraces;
+
+  void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
 
   Json::Value DumpPaths();
 
@@ -814,6 +817,7 @@ DirectoryObject::DirectoryObject(cmLocalGenerator const* lg,
   , TopSource(lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
   , TopBuild(
       lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
+  , Backtraces(this->TopSource)
 {
 }
 
@@ -821,9 +825,18 @@ Json::Value DirectoryObject::Dump()
 {
   Json::Value directoryObject = Json::objectValue;
   directoryObject["paths"] = this->DumpPaths();
+  directoryObject["backtraceGraph"] = this->Backtraces.Dump();
   return directoryObject;
 }
 
+void DirectoryObject::AddBacktrace(Json::Value& object,
+                                   cmListFileBacktrace const& bt)
+{
+  if (JBTIndex backtrace = this->Backtraces.Add(bt)) {
+    object["backtrace"] = backtrace.Index;
+  }
+}
+
 Json::Value DirectoryObject::DumpPaths()
 {
   Json::Value paths = Json::objectValue;
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
index 0e5b3b9..900faf9 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
@@ -98,11 +98,13 @@ def check_directory(c):
             d = json.load(f)
 
         assert is_dict(d)
-        assert sorted(d.keys()) == ["paths"]
+        assert sorted(d.keys()) == ["backtraceGraph", "paths"]
 
         assert is_string(d["paths"]["source"], actual["source"])
         assert is_string(d["paths"]["build"], actual["build"])
 
+        check_backtrace_graph(d["backtraceGraph"])
+
     return _check
 
 def check_backtrace_graph(btg):
-- 
cgit v0.12


From 049bf98f63f386bdc174c3872c7ef1c658041cf4 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Thu, 21 Jan 2021 13:17:19 -0500
Subject: fileapi: Add installers to codemodel-v2 "directory" object

Co-Authored-by: Kyle Edwards <kyle.edwards@kitware.com>
---
 Help/manual/cmake-file-api.7.rst                   | 148 ++++++
 Help/release/dev/fileapi-codemodel-directory.rst   |   2 +
 Source/cmFileAPICodemodel.cxx                      | 220 ++++++++-
 Tests/RunCMake/FileAPI/codemodel-v2-check.py       |  93 +++-
 .../codemodel-v2-data/directories/alias.json       |   3 +-
 .../codemodel-v2-data/directories/custom.json      |   3 +-
 .../FileAPI/codemodel-v2-data/directories/cxx.json |   3 +-
 .../FileAPI/codemodel-v2-data/directories/dir.json |   3 +-
 .../codemodel-v2-data/directories/dir_dir.json     |   3 +-
 .../codemodel-v2-data/directories/external.json    |  66 ++-
 .../codemodel-v2-data/directories/imported.json    |   3 +-
 .../codemodel-v2-data/directories/interface.json   |   3 +-
 .../codemodel-v2-data/directories/object.json      |  66 ++-
 .../FileAPI/codemodel-v2-data/directories/top.json | 546 ++++++++++++++++++++-
 14 files changed, 1148 insertions(+), 14 deletions(-)

diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 088ec2e..cbc3d6d 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -666,6 +666,154 @@ with members:
     directory (with ``.`` for the top-level build directory itself).
     Otherwise the path is absolute.
 
+``installers``
+  A JSON array of entries corresponding to :command:`install` rules.
+  Each entry is a JSON object containing members:
+
+  ``component``
+    A string specifying the component selected by the corresponding
+    :command:`install` command invocation.
+
+  ``destination``
+    Optional member that is present for specific ``type`` values below.
+    The value is a string specifying the install destination path.
+    The path may be absolute or relative to the install prefix.
+
+  ``paths``
+    Optional member that is present for specific ``type`` values below.
+    The value is a JSON array of entries corresponding to the paths
+    (files or directories) to be installed.  Each entry is one of:
+
+    * A string specifying the path from which a file or directory
+      is to be installed.  The portion of the path not preceded by
+      a ``/`` also specifies the path (name) to which the file
+      or directory is to be installed under the destination.
+
+    * A JSON object with members:
+
+      ``from``
+        A string specifying the path from which a file or directory
+        is to be installed.
+
+      ``to``
+        A string specifying the path to which the file or directory
+        is to be installed under the destination.
+
+    In both cases the paths are represented with forward slashes.  If
+    the "from" path is inside the top-level directory documented by the
+    corresponding ``type`` value, then the path is specified relative
+    to that directory.  Otherwise the path is absolute.
+
+  ``type``
+    A string specifying the type of installation rule.  The value is one
+    of the following, with some variants providing additional members:
+
+    ``file``
+      An :command:`install(FILES)` or :command:`install(PROGRAMS)` call.
+      The ``destination`` and ``paths`` members are populated, with paths
+      under the top-level *source* directory expressed relative to it.
+      The ``isOptional`` member may exist.
+      This type has no additional members.
+
+    ``directory``
+      An :command:`install(DIRECTORY)` call.
+      The ``destination`` and ``paths`` members are populated, with paths
+      under the top-level *source* directory expressed relative to it.
+      The ``isOptional`` member may exist.
+      This type has no additional members.
+
+    ``target``
+      An :command:`install(TARGETS)` call.
+      The ``destination`` and ``paths`` members are populated, with paths
+      under the top-level *build* directory expressed relative to it.
+      The ``isOptional`` member may exist.
+      This type has additional members ``targetId``, ``targetIndex``,
+      ``targetIsImportLibrary``, and ``targetInstallNamelink``.
+
+    ``export``
+      An :command:`install(EXPORT)` call.
+      The ``destination`` and ``paths`` members are populated, with paths
+      under the top-level *build* directory expressed relative to it.
+      The ``paths`` entries refer to files generated automatically by
+      CMake for installation, and their actual values are considered
+      private implementation details.
+      This type has additional members ``exportName`` and ``exportTargets``.
+
+    ``script``
+      An :command:`install(SCRIPT)` call.
+      This type has additional member ``scriptFile``.
+
+    ``code``
+      An :command:`install(CODE)` call.
+      This type has no additional members.
+
+  ``isExcludeFromAll``
+    Optional member that is present with boolean value ``true`` when
+    :command:`install` is called with the ``EXCLUDE_FROM_ALL`` option.
+
+  ``isOptional``
+    Optional member that is present with boolean value ``true`` when
+    :command:`install` is called with the ``OPTIONAL`` option.
+    This is allowed when ``type`` is ``file``, ``directory``, or ``target``.
+
+  ``targetId``
+    Optional member that is present when ``type`` is ``target``.
+    The value is a string uniquely identifying the target to be installed.
+    This matches the ``id`` member of the target in the main
+    "codemodel" object's ``targets`` array.
+
+  ``targetIndex``
+    Optional member that is present when ``type`` is ``target``.
+    The value is an unsigned integer 0-based index into the main "codemodel"
+    object's ``targets`` array for the target to be installed.
+
+  ``targetIsImportLibrary``
+    Optional member that is present when ``type`` is ``target`` and
+    the installer is for a Windows DLL import library file or for an
+    AIX linker import file.  If present, it has boolean value ``true``.
+
+  ``targetInstallNamelink``
+    Optional member that is present when ``type`` is ``target`` and
+    the installer corresponds to a target that may use symbolic links
+    to implement the :prop_tgt:`VERSION` and :prop_tgt:`SOVERSION`
+    target properties.
+    The value is a string indicating how the installer is supposed to
+    handle the symlinks: ``skip`` means the installer should skip the
+    symlinks and install only the real file, and ``only`` means the
+    installer should install only the symlinks and not the real file.
+    In all cases the ``paths`` member lists what it actually installs.
+
+  ``exportName``
+    Optional member that is present when ``type`` is ``export``.
+    The value is a string specifying the name of the export.
+
+  ``exportTargets``
+    Optional member that is present when ``type`` is ``export``.
+    The value is a JSON array of entries corresponding to the targets
+    included in the export.  Each entry is a JSON object with members:
+
+    ``id``
+      A string uniquely identifying the target.  This matches
+      the ``id`` member of the target in the main "codemodel"
+      object's ``targets`` array.
+
+    ``index``
+      An unsigned integer 0-based index into the main "codemodel"
+      object's ``targets`` array for the target.
+
+  ``scriptFile``
+    Optional member that is present when ``type`` is ``script``.
+    The value is a string specifying the path to the script file on disk,
+    represented with forward slashes.  If the file is inside the top-level
+    source directory then the path is specified relative to that directory.
+    Otherwise the path is absolute.
+
+  ``backtrace``
+    Optional member that is present when a CMake language backtrace to
+    the :command:`install` or other command invocation that added this
+    installer is available.  The value is an unsigned integer 0-based
+    index into the ``backtraceGraph`` member's ``nodes`` array.
+
 ``backtraceGraph``
   A `"codemodel" version 2 "backtrace graph"`_ whose nodes are referenced
   from ``backtrace`` members elsewhere in this "directory" object.
diff --git a/Help/release/dev/fileapi-codemodel-directory.rst b/Help/release/dev/fileapi-codemodel-directory.rst
index 7dffb96..f6515fd 100644
--- a/Help/release/dev/fileapi-codemodel-directory.rst
+++ b/Help/release/dev/fileapi-codemodel-directory.rst
@@ -6,3 +6,5 @@ fileapi-codemodel-directory
 
 * The :manual:`cmake-file-api(7)` "codemodel" version 2 gained a
   new "directory" object containing directory-level information.
+  This includes a list of installers generated by the :command:`install`
+  command.
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index e7bfc61..6b8757c 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -20,11 +20,16 @@
 #include <cm3p/json/value.h>
 
 #include "cmCryptoHash.h"
+#include "cmExportSet.h"
 #include "cmFileAPI.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmInstallDirectoryGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallFilesGenerator.h"
 #include "cmInstallGenerator.h"
+#include "cmInstallScriptGenerator.h"
 #include "cmInstallSubdirectoryGenerator.h"
 #include "cmInstallTargetGenerator.h"
 #include "cmLinkLineComputer.h"
@@ -42,6 +47,7 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTargetDepend.h"
+#include "cmTargetExport.h"
 #include "cmake.h"
 
 namespace {
@@ -377,6 +383,7 @@ class DirectoryObject
 {
   cmLocalGenerator const* LG = nullptr;
   std::string const& Config;
+  TargetIndexMapType& TargetIndexMap;
   std::string TopSource;
   std::string TopBuild;
   BacktraceData Backtraces;
@@ -384,9 +391,16 @@ class DirectoryObject
   void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
 
   Json::Value DumpPaths();
+  Json::Value DumpInstallers();
+  Json::Value DumpInstaller(cmInstallGenerator* gen);
+  Json::Value DumpInstallerExportTargets(cmExportSet* exp);
+  Json::Value DumpInstallerPath(std::string const& top,
+                                std::string const& fromPathIn,
+                                std::string const& toPath);
 
 public:
-  DirectoryObject(cmLocalGenerator const* lg, std::string const& config);
+  DirectoryObject(cmLocalGenerator const* lg, std::string const& config,
+                  TargetIndexMapType& targetIndexMap);
   Json::Value Dump();
 };
 
@@ -763,7 +777,7 @@ Json::Value CodemodelConfig::DumpDirectoryObject(Directory& d)
     prefix += "-" + this->Config;
   }
 
-  DirectoryObject dir(d.LocalGenerator, this->Config);
+  DirectoryObject dir(d.LocalGenerator, this->Config, this->TargetIndexMap);
   return this->FileAPI.MaybeJsonFile(dir.Dump(), prefix);
 }
 
@@ -811,9 +825,11 @@ Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s)
 }
 
 DirectoryObject::DirectoryObject(cmLocalGenerator const* lg,
-                                 std::string const& config)
+                                 std::string const& config,
+                                 TargetIndexMapType& targetIndexMap)
   : LG(lg)
   , Config(config)
+  , TargetIndexMap(targetIndexMap)
   , TopSource(lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
   , TopBuild(
       lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
@@ -825,6 +841,7 @@ Json::Value DirectoryObject::Dump()
 {
   Json::Value directoryObject = Json::objectValue;
   directoryObject["paths"] = this->DumpPaths();
+  directoryObject["installers"] = this->DumpInstallers();
   directoryObject["backtraceGraph"] = this->Backtraces.Dump();
   return directoryObject;
 }
@@ -850,6 +867,203 @@ Json::Value DirectoryObject::DumpPaths()
   return paths;
 }
 
+Json::Value DirectoryObject::DumpInstallers()
+{
+  Json::Value installers = Json::arrayValue;
+  for (const auto& gen : this->LG->GetMakefile()->GetInstallGenerators()) {
+    Json::Value installer = this->DumpInstaller(gen.get());
+    if (!installer.empty()) {
+      installers.append(std::move(installer)); // NOLINT(*)
+    }
+  }
+  return installers;
+}
+
+Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
+{
+  Json::Value installer = Json::objectValue;
+
+  // Exclude subdirectory installers.  They are implementation details.
+  if (dynamic_cast<cmInstallSubdirectoryGenerator*>(gen)) {
+    return installer;
+  }
+
+  // Exclude installers not used in this configuration.
+  if (!gen->InstallsForConfig(this->Config)) {
+    return installer;
+  }
+
+  // Add fields specific to each kind of install generator.
+  if (auto* installTarget = dynamic_cast<cmInstallTargetGenerator*>(gen)) {
+    cmInstallTargetGenerator::Files const& files =
+      installTarget->GetFiles(this->Config);
+    if (files.From.empty()) {
+      return installer;
+    }
+
+    installer["type"] = "target";
+    installer["destination"] = installTarget->GetDestination(this->Config);
+    installer["targetId"] =
+      TargetId(installTarget->GetTarget(), this->TopBuild);
+    installer["targetIndex"] =
+      this->TargetIndexMap[installTarget->GetTarget()];
+
+    std::string fromDir = files.FromDir;
+    if (!fromDir.empty()) {
+      fromDir.push_back('/');
+    }
+
+    std::string toDir = files.ToDir;
+    if (!toDir.empty()) {
+      toDir.push_back('/');
+    }
+
+    Json::Value paths = Json::arrayValue;
+    for (size_t i = 0; i < files.From.size(); ++i) {
+      std::string const& fromPath = cmStrCat(fromDir, files.From[i]);
+      std::string const& toPath = cmStrCat(toDir, files.To[i]);
+      paths.append(this->DumpInstallerPath(this->TopBuild, fromPath, toPath));
+    }
+    installer["paths"] = std::move(paths);
+
+    if (installTarget->GetOptional()) {
+      installer["isOptional"] = true;
+    }
+
+    if (installTarget->IsImportLibrary()) {
+      installer["targetIsImportLibrary"] = true;
+    }
+
+    switch (files.NamelinkMode) {
+      case cmInstallTargetGenerator::NamelinkModeNone:
+        break;
+      case cmInstallTargetGenerator::NamelinkModeOnly:
+        installer["targetInstallNamelink"] = "only";
+        break;
+      case cmInstallTargetGenerator::NamelinkModeSkip:
+        installer["targetInstallNamelink"] = "skip";
+        break;
+    }
+
+    // FIXME: Parse FilePermissions to provide structured information.
+    // FIXME: Thread EXPORT name through from install() call.
+  } else if (auto* installFiles =
+               dynamic_cast<cmInstallFilesGenerator*>(gen)) {
+    std::vector<std::string> const& files =
+      installFiles->GetFiles(this->Config);
+    if (files.empty()) {
+      return installer;
+    }
+
+    installer["type"] = "file";
+    installer["destination"] = installFiles->GetDestination(this->Config);
+    Json::Value paths = Json::arrayValue;
+    std::string const& rename = installFiles->GetRename(this->Config);
+    if (!rename.empty() && files.size() == 1) {
+      paths.append(this->DumpInstallerPath(this->TopSource, files[0], rename));
+    } else {
+      for (std::string const& file : installFiles->GetFiles(this->Config)) {
+        paths.append(RelativeIfUnder(this->TopSource, file));
+      }
+    }
+    installer["paths"] = std::move(paths);
+    if (installFiles->GetOptional()) {
+      installer["isOptional"] = true;
+    }
+    // FIXME: Parse FilePermissions to provide structured information.
+  } else if (auto* installDir =
+               dynamic_cast<cmInstallDirectoryGenerator*>(gen)) {
+    std::vector<std::string> const& dirs =
+      installDir->GetDirectories(this->Config);
+    if (dirs.empty()) {
+      return installer;
+    }
+
+    installer["type"] = "directory";
+    installer["destination"] = installDir->GetDestination(this->Config);
+    Json::Value paths = Json::arrayValue;
+    for (std::string const& dir : dirs) {
+      if (cmHasLiteralSuffix(dir, "/")) {
+        paths.append(this->DumpInstallerPath(
+          this->TopSource, dir.substr(0, dir.size() - 1), "."));
+      } else {
+        paths.append(this->DumpInstallerPath(
+          this->TopSource, dir, cmSystemTools::GetFilenameName(dir)));
+      }
+    }
+    installer["paths"] = std::move(paths);
+    if (installDir->GetOptional()) {
+      installer["isOptional"] = true;
+    }
+    // FIXME: Parse FilePermissions, DirPermissions, and LiteralArguments.
+    // to provide structured information.
+  } else if (auto* installExport =
+               dynamic_cast<cmInstallExportGenerator*>(gen)) {
+    installer["type"] = "export";
+    installer["destination"] = installExport->GetDestination();
+    cmExportSet* exportSet = installExport->GetExportSet();
+    installer["exportName"] = exportSet->GetName();
+    installer["exportTargets"] = this->DumpInstallerExportTargets(exportSet);
+    Json::Value paths = Json::arrayValue;
+    paths.append(
+      RelativeIfUnder(this->TopBuild, installExport->GetMainImportFile()));
+    installer["paths"] = std::move(paths);
+  } else if (auto* installScript =
+               dynamic_cast<cmInstallScriptGenerator*>(gen)) {
+    if (installScript->IsCode()) {
+      installer["type"] = "code";
+    } else {
+      installer["type"] = "script";
+      installer["scriptFile"] = RelativeIfUnder(
+        this->TopSource, installScript->GetScript(this->Config));
+    }
+  }
+
+  // Add fields common to all install generators.
+  installer["component"] = gen->GetComponent();
+  if (gen->GetExcludeFromAll()) {
+    installer["isExcludeFromAll"] = true;
+  }
+  this->AddBacktrace(installer, gen->GetBacktrace());
+
+  return installer;
+}
+
+Json::Value DirectoryObject::DumpInstallerExportTargets(cmExportSet* exp)
+{
+  Json::Value targets = Json::arrayValue;
+  for (auto const& targetExport : exp->GetTargetExports()) {
+    Json::Value target = Json::objectValue;
+    target["id"] = TargetId(targetExport->Target, this->TopBuild);
+    target["index"] = this->TargetIndexMap[targetExport->Target];
+    targets.append(std::move(target)); // NOLINT(*)
+  }
+  return targets;
+}
+
+Json::Value DirectoryObject::DumpInstallerPath(std::string const& top,
+                                               std::string const& fromPathIn,
+                                               std::string const& toPath)
+{
+  Json::Value installPath;
+
+  std::string fromPath = RelativeIfUnder(top, fromPathIn);
+
+  // If toPath is the last component of fromPath, use just fromPath.
+  if (toPath.find_first_of('/') == std::string::npos &&
+      cmHasSuffix(fromPath, toPath) &&
+      (fromPath.size() == toPath.size() ||
+       fromPath[fromPath.size() - toPath.size() - 1] == '/')) {
+    installPath = fromPath;
+  } else {
+    installPath = Json::objectValue;
+    installPath["from"] = fromPath;
+    installPath["to"] = toPath;
+  }
+
+  return installPath;
+}
+
 Target::Target(cmGeneratorTarget* gt, std::string const& config)
   : GT(gt)
   , Config(config)
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
index 900faf9..0d718a4 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
@@ -98,13 +98,90 @@ def check_directory(c):
             d = json.load(f)
 
         assert is_dict(d)
-        assert sorted(d.keys()) == ["backtraceGraph", "paths"]
+        assert sorted(d.keys()) == ["backtraceGraph", "installers", "paths"]
 
         assert is_string(d["paths"]["source"], actual["source"])
         assert is_string(d["paths"]["build"], actual["build"])
 
         check_backtrace_graph(d["backtraceGraph"])
 
+        assert is_list(d["installers"])
+        assert len(d["installers"]) == len(expected["installers"])
+        for a, e in zip(d["installers"], expected["installers"]):
+            assert is_dict(a)
+            expected_keys = ["component", "type"]
+
+            assert is_string(a["component"], e["component"])
+            assert is_string(a["type"], e["type"])
+
+            if e["destination"] is not None:
+                expected_keys.append("destination")
+                assert is_string(a["destination"], e["destination"])
+
+            if e["paths"] is not None:
+                expected_keys.append("paths")
+                assert is_list(a["paths"])
+                assert len(a["paths"]) == len(e["paths"])
+
+                for ap, ep in zip(a["paths"], e["paths"]):
+                    if is_string(ep):
+                        assert matches(ap, ep)
+                    else:
+                        assert is_dict(ap)
+                        assert sorted(ap.keys()) == ["from", "to"]
+                        assert matches(ap["from"], ep["from"])
+                        assert matches(ap["to"], ep["to"])
+
+            if e["isExcludeFromAll"] is not None:
+                expected_keys.append("isExcludeFromAll")
+                assert is_bool(a["isExcludeFromAll"], e["isExcludeFromAll"])
+
+            if e["isOptional"] is not None:
+                expected_keys.append("isOptional")
+                assert is_bool(a["isOptional"], e["isOptional"])
+
+            if e["targetId"] is not None:
+                expected_keys.append("targetId")
+                assert matches(a["targetId"], e["targetId"])
+
+            if e["targetIndex"] is not None:
+                expected_keys.append("targetIndex")
+                assert is_int(a["targetIndex"])
+                assert c["targets"][a["targetIndex"]]["name"] == e["targetIndex"]
+
+            if e["targetIsImportLibrary"] is not None:
+                expected_keys.append("targetIsImportLibrary")
+                assert is_bool(a["targetIsImportLibrary"], e["targetIsImportLibrary"])
+
+            if e["targetInstallNamelink"] is not None:
+                expected_keys.append("targetInstallNamelink")
+                assert is_string(a["targetInstallNamelink"], e["targetInstallNamelink"])
+
+            if e["exportName"] is not None:
+                expected_keys.append("exportName")
+                assert is_string(a["exportName"], e["exportName"])
+
+            if e["exportTargets"] is not None:
+                expected_keys.append("exportTargets")
+                assert is_list(a["exportTargets"])
+                assert len(a["exportTargets"]) == len(e["exportTargets"])
+                for at, et in zip(a["exportTargets"], e["exportTargets"]):
+                    assert is_dict(at)
+                    assert sorted(at.keys()) == ["id", "index"]
+                    assert matches(at["id"], et["id"])
+                    assert is_int(at["index"])
+                    assert c["targets"][at["index"]]["name"] == et["index"]
+
+            if e["scriptFile"] is not None:
+                expected_keys.append("scriptFile")
+                assert is_string(a["scriptFile"], e["scriptFile"])
+
+            if e["backtrace"] is not None:
+                expected_keys.append("backtrace")
+                check_backtrace(d, a["backtrace"], e["backtrace"])
+
+            assert sorted(a.keys()) == sorted(expected_keys)
+
     return _check
 
 def check_backtrace_graph(btg):
@@ -555,6 +632,20 @@ def gen_check_directories(c, g):
         for e in expected:
             e["targetIds"] = filter_list(lambda t: not matches(t, "^\\^(ALL_BUILD|ZERO_CHECK)"), e["targetIds"])
 
+    if sys.platform in ("win32", "cygwin", "msys") or "aix" in sys.platform:
+        for e in expected:
+            e["installers"] = list(filter(lambda i: i["targetInstallNamelink"] is None or i["targetInstallNamelink"] == "skip", e["installers"]))
+            for i in e["installers"]:
+                i["targetInstallNamelink"] = None
+
+    if sys.platform not in ("win32", "cygwin", "msys"):
+        for e in expected:
+            e["installers"] = list(filter(lambda i: "_dllExtra" not in i or not i["_dllExtra"], e["installers"]))
+            if "aix" not in sys.platform:
+                for i in e["installers"]:
+                    if "pathsNamelink" in i:
+                        i["paths"] = i["pathsNamelink"]
+
     return expected
 
 def check_directories(c, g):
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/alias.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/alias.json
index 9f0c48a..6514910 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/alias.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/alias.json
@@ -11,5 +11,6 @@
     ],
     "projectName": "Alias",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/custom.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/custom.json
index afd41f3..c89e4f9 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/custom.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/custom.json
@@ -11,5 +11,6 @@
     ],
     "projectName": "Custom",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json
index a51b6eb..7168306 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json
@@ -17,5 +17,6 @@
     ],
     "projectName": "Cxx",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json
index afbd43a..8509f08 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json
@@ -8,5 +8,6 @@
     "targetIds": null,
     "projectName": "codemodel-v2",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_dir.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_dir.json
index 3737ad5..27184cd 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_dir.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_dir.json
@@ -6,5 +6,6 @@
     "targetIds": null,
     "projectName": "codemodel-v2",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json
index 0d3161c..55dd573 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json
@@ -10,5 +10,69 @@
     ],
     "projectName": "External",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": true
+    "hasInstallRule": true,
+    "installers": [
+        {
+            "component": "Unspecified",
+            "type": "directory",
+            "destination": "dir3",
+            "paths": [
+                "^.*/Tests/RunCMake/FileAPIExternalSource/\\.$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^.*/Tests/RunCMake/FileAPIExternalSource/CMakeLists\\.txt$",
+                    "line": 15,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^.*/Tests/RunCMake/FileAPIExternalSource/CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "directory",
+            "destination": "dir4",
+            "paths": [
+                "^.*/Tests/RunCMake/FileAPIExternalSource$"
+            ],
+            "isExcludeFromAll": true,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^.*/Tests/RunCMake/FileAPIExternalSource/CMakeLists\\.txt$",
+                    "line": 16,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^.*/Tests/RunCMake/FileAPIExternalSource/CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        }
+    ]
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json
index a41b79b..d127274 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json
@@ -14,5 +14,6 @@
     ],
     "projectName": "Imported",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/interface.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/interface.json
index b10d496..90664dc 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/interface.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/interface.json
@@ -10,5 +10,6 @@
     ],
     "projectName": "Interface",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/object.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/object.json
index 1e647ad..ef2dd0b 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/object.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/object.json
@@ -13,5 +13,69 @@
     ],
     "projectName": "Object",
     "minimumCMakeVersion": "3.13",
-    "hasInstallRule": true
+    "hasInstallRule": true,
+    "installers": [
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "bin",
+            "paths": [
+                "^object/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?c_object_exe(\\.exe)?$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^c_object_exe::@5ed5358f70faf8d8af7a$",
+            "targetIndex": "c_object_exe",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^object/CMakeLists\\.txt$",
+                    "line": 13,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^object/CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "bin",
+            "paths": [
+                "^object/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?cxx_object_exe(\\.exe)?$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^cxx_object_exe::@5ed5358f70faf8d8af7a$",
+            "targetIndex": "cxx_object_exe",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^object/CMakeLists\\.txt$",
+                    "line": 13,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^object/CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        }
+    ]
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json
index 736d1f5..ce45947 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json
@@ -25,5 +25,549 @@
     ],
     "projectName": "codemodel-v2",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": true
+    "hasInstallRule": true,
+    "installers": [
+        {
+            "component": "Tools",
+            "type": "target",
+            "destination": "bin",
+            "paths": [
+                "^cxx/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?cxx_exe(\\.exe)?$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^cxx_exe::@a56b12a3f5c0529fb296$",
+            "targetIndex": "cxx_exe",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 38,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "lib",
+            "paths": [
+                "^((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib)?c_shared_lib\\.(lib|dll\\.a)$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^c_shared_lib::@6890427a1f51a3e7e1df$",
+            "targetIndex": "c_shared_lib",
+            "targetIsImportLibrary": true,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "_dllExtra": true,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 41,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "lib",
+            "paths": [
+                "^lib/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib|cyg)?c_shared_lib(-1)?\\.(dll|so)$"
+            ],
+            "pathsNamelink": [
+                "^lib/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib)?c_shared_lib\\.(so\\.1\\.2\\.3|1\\.2\\.3\\.dylib)$",
+                "^lib/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib)?c_shared_lib\\.(so\\.1|1\\.dylib)$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^c_shared_lib::@6890427a1f51a3e7e1df$",
+            "targetIndex": "c_shared_lib",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": "skip",
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 41,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "lib",
+            "paths": [
+                "^cxx/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib)?cxx_shared_lib\\.(lib|dll\\.a)$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^cxx_shared_lib::@a56b12a3f5c0529fb296$",
+            "targetIndex": "cxx_shared_lib",
+            "targetIsImportLibrary": true,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "_dllExtra": true,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 41,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "lib",
+            "paths": [
+                "^cxx/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib|cyg)?cxx_shared_lib\\.(dll|so|dylib)$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^cxx_shared_lib::@a56b12a3f5c0529fb296$",
+            "targetIndex": "cxx_shared_lib",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 41,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "lib",
+            "paths": [
+                "^lib/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib)?c_shared_lib\\.(dll|so|dylib)$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^c_shared_lib::@6890427a1f51a3e7e1df$",
+            "targetIndex": "c_shared_lib",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": "only",
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 46,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "file",
+            "destination": "include",
+            "paths": [
+                {
+                    "from": "^empty\\.h$",
+                    "to": "^empty-renamed\\.h$"
+                }
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": true,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 48,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "file",
+            "destination": "include",
+            "paths": [
+                "^codemodel-v2\\.cmake$",
+                "^empty\\.h$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 49,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "directory",
+            "destination": "dir1",
+            "paths": [
+                "^\\.$",
+                "^dir$",
+                {
+                    "from": "^cxx$",
+                    "to": "^\\.$"
+                }
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": true,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 50,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "directory",
+            "destination": "dir2",
+            "paths": [
+                {
+                    "from": "^\\.$",
+                    "to": "^FileAPI$"
+                },
+                "^dir$",
+                {
+                    "from": "^cxx$",
+                    "to": "^\\.$"
+                }
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 51,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "export",
+            "destination": "lib/cmake/foo",
+            "paths": [
+                "^CMakeFiles/Export/lib/cmake/foo/FooTargets\\.cmake$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": "FooTargets",
+            "exportTargets": [
+                {
+                    "id": "^cxx_exe::@a56b12a3f5c0529fb296$",
+                    "index": "cxx_exe"
+                }
+            ],
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 52,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "script",
+            "destination": null,
+            "paths": null,
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": "InstallScript.cmake",
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 53,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        }
+    ]
 }
-- 
cgit v0.12