Browse Source

CMakePresets: Add include field

Fixes: #21331
Kyle Edwards 3 years ago
parent
commit
26a5512c0f
42 changed files with 351 additions and 7 deletions
  1. 25 3
      Help/manual/cmake-presets.7.rst
  2. 1 1
      Help/manual/presets/example.json
  3. 22 0
      Help/manual/presets/schema.json
  4. 6 0
      Help/release/dev/cmake-presets-include.rst
  5. 6 0
      Source/cmCMakePresetsGraph.cxx
  6. 3 0
      Source/cmCMakePresetsGraph.h
  7. 57 3
      Source/cmCMakePresetsGraphReadJSON.cxx
  8. 8 0
      Tests/RunCMake/CMakePresets/Include-stdout.txt
  9. 16 0
      Tests/RunCMake/CMakePresets/Include.json.in
  10. 8 0
      Tests/RunCMake/CMakePresets/IncludeCommon.json.in
  11. 1 0
      Tests/RunCMake/CMakePresets/IncludeCycle-result.txt
  12. 2 0
      Tests/RunCMake/CMakePresets/IncludeCycle-stderr.txt
  13. 11 0
      Tests/RunCMake/CMakePresets/IncludeCycle.json.in
  14. 1 0
      Tests/RunCMake/CMakePresets/IncludeCycle3Files-result.txt
  15. 2 0
      Tests/RunCMake/CMakePresets/IncludeCycle3Files-stderr.txt
  16. 6 0
      Tests/RunCMake/CMakePresets/IncludeCycle3Files.json.in
  17. 6 0
      Tests/RunCMake/CMakePresets/IncludeCycle3Files2.json.in
  18. 6 0
      Tests/RunCMake/CMakePresets/IncludeCycle3Files3.json.in
  19. 3 0
      Tests/RunCMake/CMakePresets/IncludeCycleUser.json.in
  20. 1 0
      Tests/RunCMake/CMakePresets/IncludeNotFound-result.txt
  21. 2 0
      Tests/RunCMake/CMakePresets/IncludeNotFound-stderr.txt
  22. 11 0
      Tests/RunCMake/CMakePresets/IncludeNotFound.json.in
  23. 1 0
      Tests/RunCMake/CMakePresets/IncludeOutsideProject-result.txt
  24. 2 0
      Tests/RunCMake/CMakePresets/IncludeOutsideProject-stderr.txt
  25. 11 0
      Tests/RunCMake/CMakePresets/IncludeOutsideProject.json.in
  26. 3 0
      Tests/RunCMake/CMakePresets/IncludeOutsideProjectInclude.json
  27. 6 0
      Tests/RunCMake/CMakePresets/IncludeOutsideProjectIntermediate.json.in
  28. 6 0
      Tests/RunCMake/CMakePresets/IncludeOutsideProjectUser.json.in
  29. 15 0
      Tests/RunCMake/CMakePresets/IncludeUser.json.in
  30. 8 0
      Tests/RunCMake/CMakePresets/IncludeUserCommon.json.in
  31. 0 0
      Tests/RunCMake/CMakePresets/IncludeUserOutsideProject.cmake
  32. 11 0
      Tests/RunCMake/CMakePresets/IncludeUserOutsideProjectUser.json.in
  33. 1 0
      Tests/RunCMake/CMakePresets/IncludeV3-result.txt
  34. 2 0
      Tests/RunCMake/CMakePresets/IncludeV3-stderr.txt
  35. 4 0
      Tests/RunCMake/CMakePresets/IncludeV3.json.in
  36. 1 0
      Tests/RunCMake/CMakePresets/IncludeV4V3-result.txt
  37. 2 0
      Tests/RunCMake/CMakePresets/IncludeV4V3-stderr.txt
  38. 6 0
      Tests/RunCMake/CMakePresets/IncludeV4V3.json.in
  39. 4 0
      Tests/RunCMake/CMakePresets/IncludeV4V3Extra.json.in
  40. 45 0
      Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
  41. 7 0
      Tests/RunCMake/CMakePresets/check.cmake
  42. 12 0
      Tests/RunCMake/CMakePresets/subdir/CMakePresets.json.in

+ 25 - 3
Help/manual/cmake-presets.7.rst

@@ -12,9 +12,10 @@ Introduction
 
 
 One problem that CMake users often face is sharing settings with other people
 One problem that CMake users often face is sharing settings with other people
 for common ways to configure a project. This may be done to support CI builds,
 for common ways to configure a project. This may be done to support CI builds,
-or for users who frequently use the same build. CMake supports two files,
+or for users who frequently use the same build. CMake supports two main files,
 ``CMakePresets.json`` and ``CMakeUserPresets.json``, that allow users to
 ``CMakePresets.json`` and ``CMakeUserPresets.json``, that allow users to
-specify common configure options and share them with others.
+specify common configure options and share them with others. CMake also
+supports files included with the ``include`` field.
 
 
 ``CMakePresets.json`` and ``CMakeUserPresets.json`` live in the project's root
 ``CMakePresets.json`` and ``CMakeUserPresets.json`` live in the project's root
 directory. They both have exactly the same format, and both are optional
 directory. They both have exactly the same format, and both are optional
@@ -26,6 +27,21 @@ builds. ``CMakePresets.json`` may be checked into a version control system, and
 is using Git, ``CMakePresets.json`` may be tracked, and
 is using Git, ``CMakePresets.json`` may be tracked, and
 ``CMakeUserPresets.json`` should be added to the ``.gitignore``.
 ``CMakeUserPresets.json`` should be added to the ``.gitignore``.
 
 
+``CMakePresets.json`` and ``CMakeUserPresets.json`` can include other files
+with the ``include`` field in file version ``4`` and later. Files included by
+these files can also include other files. If a preset file contains presets
+that inherit from presets in another file, the file must include the other file
+either directly or indirectly. Include cycles are not allowed among files (if
+``a.json`` includes ``b.json``, ``b.json`` cannot include ``a.json``). However,
+a file may be included multiple times from the same file or from different
+files. If ``CMakePresets.json`` and ``CMakeUserPresets.json`` are both present,
+``CMakeUserPresets.json`` implicitly includes ``CMakePresets.json``, even with
+no ``include`` field, in all versions of the format. Files directly or
+indirectly included from ``CMakePresets.json`` must be inside the project
+directory. This restriction does not apply to ``CMakeUserPresets.json`` and
+files that it includes, unless those files are also included by
+``CMakePresets.json``.
+
 Format
 Format
 ======
 ======
 
 
@@ -39,7 +55,7 @@ The root object recognizes the following fields:
 ``version``
 ``version``
 
 
   A required integer representing the version of the JSON schema.
   A required integer representing the version of the JSON schema.
-  The supported versions are ``1``, ``2``, and ``3``.
+  The supported versions are ``1``, ``2``, ``3``, and ``4``.
 
 
 ``cmakeMinimumRequired``
 ``cmakeMinimumRequired``
 
 
@@ -82,6 +98,12 @@ The root object recognizes the following fields:
   An optional array of `Test Preset`_ objects.
   An optional array of `Test Preset`_ objects.
   This is allowed in preset files specifying version ``2`` or above.
   This is allowed in preset files specifying version ``2`` or above.
 
 
+``include``
+
+  An optional array of strings representing files to include. If the filenames
+  are not absolute, they are considered relative to the current file.
+  This is allowed in preset files specifying version ``4`` or above.
+
 Configure Preset
 Configure Preset
 ^^^^^^^^^^^^^^^^
 ^^^^^^^^^^^^^^^^
 
 

+ 1 - 1
Help/manual/presets/example.json

@@ -1,5 +1,5 @@
 {
 {
-  "version": 3,
+  "version": 4,
   "cmakeMinimumRequired": {
   "cmakeMinimumRequired": {
     "major": 3,
     "major": 3,
     "minor": 21,
     "minor": 21,

+ 22 - 0
Help/manual/presets/schema.json

@@ -42,6 +42,21 @@
         "testPresets": { "$ref": "#/definitions/testPresetsV3"}
         "testPresets": { "$ref": "#/definitions/testPresetsV3"}
       },
       },
       "additionalProperties": false
       "additionalProperties": false
+    },
+    {
+      "properties": {
+        "version": {
+          "const": 4,
+          "description": "A required integer representing the version of the JSON schema."
+        },
+        "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
+        "vendor": { "$ref": "#/definitions/vendor" },
+        "configurePresets": { "$ref": "#/definitions/configurePresetsV3"},
+        "buildPresets": { "$ref": "#/definitions/buildPresetsV3"},
+        "testPresets": { "$ref": "#/definitions/testPresetsV3"},
+        "include": { "$ref": "#/definitions/include"}
+      },
+      "additionalProperties": false
     }
     }
   ],
   ],
   "required": [
   "required": [
@@ -1235,6 +1250,13 @@
           "description": "Null indicates that the condition always evaluates to true and is not inherited."
           "description": "Null indicates that the condition always evaluates to true and is not inherited."
         }
         }
       ]
       ]
+    },
+    "include": {
+      "type": "array",
+      "description": "An optional array of strings representing files to include. If the filenames are not absolute, they are considered relative to the current file.",
+      "items": {
+        "type": "string"
+      }
     }
     }
   }
   }
 }
 }

+ 6 - 0
Help/release/dev/cmake-presets-include.rst

@@ -0,0 +1,6 @@
+cmake-presets-include
+---------------------
+
+* :manual:`cmake-presets(7)` files now support schema version ``4``.
+* :manual:`cmake-presets(7)` files now have an optional ``include`` field,
+  which allows the files to include other files.

+ 6 - 0
Source/cmCMakePresetsGraph.cxx

@@ -996,6 +996,10 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result)
     case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED:
     case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED:
       return "File version must be 2 or higher for build and test preset "
       return "File version must be 2 or higher for build and test preset "
              "support.";
              "support.";
+    case ReadFileResult::INCLUDE_UNSUPPORTED:
+      return "File version must be 4 or higher for include support";
+    case ReadFileResult::INVALID_INCLUDE:
+      return "Invalid \"include\" field";
     case ReadFileResult::INVALID_CONFIGURE_PRESET:
     case ReadFileResult::INVALID_CONFIGURE_PRESET:
       return "Invalid \"configurePreset\" field";
       return "Invalid \"configurePreset\" field";
     case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED:
     case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED:
@@ -1010,6 +1014,8 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result)
              "support.";
              "support.";
     case ReadFileResult::CYCLIC_INCLUDE:
     case ReadFileResult::CYCLIC_INCLUDE:
       return "Cyclic include among preset files";
       return "Cyclic include among preset files";
+    case ReadFileResult::INCLUDE_OUTSIDE_PROJECT:
+      return "File included from outside project directory";
   }
   }
 
 
   return "Unknown error";
   return "Unknown error";

+ 3 - 0
Source/cmCMakePresetsGraph.h

@@ -36,12 +36,15 @@ public:
     PRESET_UNREACHABLE_FROM_FILE,
     PRESET_UNREACHABLE_FROM_FILE,
     INVALID_MACRO_EXPANSION,
     INVALID_MACRO_EXPANSION,
     BUILD_TEST_PRESETS_UNSUPPORTED,
     BUILD_TEST_PRESETS_UNSUPPORTED,
+    INCLUDE_UNSUPPORTED,
+    INVALID_INCLUDE,
     INVALID_CONFIGURE_PRESET,
     INVALID_CONFIGURE_PRESET,
     INSTALL_PREFIX_UNSUPPORTED,
     INSTALL_PREFIX_UNSUPPORTED,
     INVALID_CONDITION,
     INVALID_CONDITION,
     CONDITION_UNSUPPORTED,
     CONDITION_UNSUPPORTED,
     TOOLCHAIN_FILE_UNSUPPORTED,
     TOOLCHAIN_FILE_UNSUPPORTED,
     CYCLIC_INCLUDE,
     CYCLIC_INCLUDE,
+    INCLUDE_OUTSIDE_PROJECT,
   };
   };
 
 
   enum class ArchToolsetStrategy
   enum class ArchToolsetStrategy

+ 57 - 3
Source/cmCMakePresetsGraphReadJSON.cxx

@@ -33,7 +33,7 @@ using TestPreset = cmCMakePresetsGraph::TestPreset;
 using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy;
 using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy;
 
 
 constexpr int MIN_VERSION = 1;
 constexpr int MIN_VERSION = 1;
-constexpr int MAX_VERSION = 3;
+constexpr int MAX_VERSION = 4;
 
 
 struct CMakeVersion
 struct CMakeVersion
 {
 {
@@ -48,6 +48,7 @@ struct RootPresets
   std::vector<cmCMakePresetsGraph::ConfigurePreset> ConfigurePresets;
   std::vector<cmCMakePresetsGraph::ConfigurePreset> ConfigurePresets;
   std::vector<cmCMakePresetsGraph::BuildPreset> BuildPresets;
   std::vector<cmCMakePresetsGraph::BuildPreset> BuildPresets;
   std::vector<cmCMakePresetsGraph::TestPreset> TestPresets;
   std::vector<cmCMakePresetsGraph::TestPreset> TestPresets;
+  std::vector<std::string> Include;
 };
 };
 
 
 std::unique_ptr<cmCMakePresetsGraphInternal::NotCondition> InvertCondition(
 std::unique_ptr<cmCMakePresetsGraphInternal::NotCondition> InvertCondition(
@@ -271,6 +272,13 @@ auto const CMakeVersionHelper =
     .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
     .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
     .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
     .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
 
 
+auto const IncludeHelper = cmJSONStringHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_INCLUDE);
+
+auto const IncludeVectorHelper =
+  cmJSONVectorHelper<std::string, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_INCLUDE, IncludeHelper);
+
 auto const RootPresetsHelper =
 auto const RootPresetsHelper =
   cmJSONObjectHelper<RootPresets, ReadFileResult>(
   cmJSONObjectHelper<RootPresets, ReadFileResult>(
     ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
     ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
@@ -283,6 +291,7 @@ auto const RootPresetsHelper =
           cmCMakePresetsGraphInternal::TestPresetsHelper, false)
           cmCMakePresetsGraphInternal::TestPresetsHelper, false)
     .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
     .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
           CMakeVersionHelper, false)
           CMakeVersionHelper, false)
+    .Bind("include"_s, &RootPresets::Include, IncludeVectorHelper, false)
     .Bind<std::nullptr_t>(
     .Bind<std::nullptr_t>(
       "vendor"_s, nullptr,
       "vendor"_s, nullptr,
       cmCMakePresetsGraphInternal::VendorHelper(ReadFileResult::INVALID_ROOT),
       cmCMakePresetsGraphInternal::VendorHelper(ReadFileResult::INVALID_ROOT),
@@ -413,6 +422,19 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
   const std::string& filename, RootType rootType, ReadReason readReason,
   const std::string& filename, RootType rootType, ReadReason readReason,
   std::vector<File*>& inProgressFiles, File*& file)
   std::vector<File*>& inProgressFiles, File*& file)
 {
 {
+  ReadFileResult result;
+
+  if (rootType == RootType::Project) {
+    auto normalizedFilename = cmSystemTools::CollapseFullPath(filename);
+
+    auto normalizedProjectDir =
+      cmSystemTools::CollapseFullPath(this->SourceDir);
+    if (!cmSystemTools::IsSubDirectory(normalizedFilename,
+                                       normalizedProjectDir)) {
+      return ReadFileResult::INCLUDE_OUTSIDE_PROJECT;
+    }
+  }
+
   for (auto const& f : this->Files) {
   for (auto const& f : this->Files) {
     if (cmSystemTools::SameFile(filename, f->Filename)) {
     if (cmSystemTools::SameFile(filename, f->Filename)) {
       file = f.get();
       file = f.get();
@@ -421,6 +443,22 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
       if (fileIt != inProgressFiles.end()) {
       if (fileIt != inProgressFiles.end()) {
         return cmCMakePresetsGraph::ReadFileResult::CYCLIC_INCLUDE;
         return cmCMakePresetsGraph::ReadFileResult::CYCLIC_INCLUDE;
       }
       }
+
+      // Check files included by this file again to make sure they're in the
+      // project directory.
+      if (rootType == RootType::Project) {
+        for (auto* f2 : file->ReachableFiles) {
+          if (!cmSystemTools::SameFile(filename, f2->Filename)) {
+            File* file2;
+            if ((result = this->ReadJSONFile(
+                   f2->Filename, rootType, ReadReason::Included,
+                   inProgressFiles, file2)) != ReadFileResult::READ_OK) {
+              return result;
+            }
+          }
+        }
+      }
+
       return cmCMakePresetsGraph::ReadFileResult::READ_OK;
       return cmCMakePresetsGraph::ReadFileResult::READ_OK;
     }
     }
   }
   }
@@ -440,8 +478,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
   }
   }
 
 
   int v = 0;
   int v = 0;
-  auto result = RootVersionHelper(v, &root);
-  if (result != ReadFileResult::READ_OK) {
+  if ((result = RootVersionHelper(v, &root)) != ReadFileResult::READ_OK) {
     return result;
     return result;
   }
   }
   if (v < MIN_VERSION || v > MAX_VERSION) {
   if (v < MIN_VERSION || v > MAX_VERSION) {
@@ -454,6 +491,11 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
     return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED;
     return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED;
   }
   }
 
 
+  // Support for include added in version 4.
+  if (v < 4 && root.isMember("include")) {
+    return ReadFileResult::INCLUDE_UNSUPPORTED;
+  }
+
   RootPresets presets;
   RootPresets presets;
   if ((result = RootPresetsHelper(presets, &root)) !=
   if ((result = RootPresetsHelper(presets, &root)) !=
       ReadFileResult::READ_OK) {
       ReadFileResult::READ_OK) {
@@ -571,6 +613,18 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
     return ReadFileResult::READ_OK;
     return ReadFileResult::READ_OK;
   };
   };
 
 
+  for (auto include : presets.Include) {
+    if (!cmSystemTools::FileIsFullPath(include)) {
+      auto directory = cmSystemTools::GetFilenamePath(filename);
+      include = cmStrCat(directory, '/', include);
+    }
+
+    if ((result = includeFile(include, rootType, ReadReason::Included)) !=
+        ReadFileResult::READ_OK) {
+      return result;
+    }
+  }
+
   if (rootType == RootType::User && readReason == ReadReason::Root) {
   if (rootType == RootType::User && readReason == ReadReason::Root) {
     auto cmakePresetsFilename = GetFilename(this->SourceDir);
     auto cmakePresetsFilename = GetFilename(this->SourceDir);
     if (cmSystemTools::FileExists(cmakePresetsFilename)) {
     if (cmSystemTools::FileExists(cmakePresetsFilename)) {

+ 8 - 0
Tests/RunCMake/CMakePresets/Include-stdout.txt

@@ -0,0 +1,8 @@
+^Not searching for unused variables given on the command line\.
+Available configure presets:
+
+  "IncludeUser"
+  "IncludeUserCommon"
+  "Include"
+  "Subdir"
+  "IncludeCommon"$

+ 16 - 0
Tests/RunCMake/CMakePresets/Include.json.in

@@ -0,0 +1,16 @@
+{
+  "version": 4,
+  "include": [
+    "subdir/CMakePresets.json",
+    "@RunCMake_TEST_SOURCE_DIR@/IncludeCommon.json"
+  ],
+  "configurePresets": [
+    {
+      "name": "Include",
+      "inherits": [
+        "IncludeCommon",
+        "Subdir"
+      ]
+    }
+  ]
+}

+ 8 - 0
Tests/RunCMake/CMakePresets/IncludeCommon.json.in

@@ -0,0 +1,8 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "IncludeCommon"
+    }
+  ]
+}

+ 1 - 0
Tests/RunCMake/CMakePresets/IncludeCycle-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresets/IncludeCycle-stderr.txt

@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/IncludeCycle: Cyclic include among preset files$

+ 11 - 0
Tests/RunCMake/CMakePresets/IncludeCycle.json.in

@@ -0,0 +1,11 @@
+{
+  "version": 4,
+  "include": [
+    "CMakeUserPresets.json"
+  ],
+  "configurePresets": [
+    {
+      "name": "IncludeCycle"
+    }
+  ]
+}

+ 1 - 0
Tests/RunCMake/CMakePresets/IncludeCycle3Files-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresets/IncludeCycle3Files-stderr.txt

@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/IncludeCycle3Files: Cyclic include among preset files$

+ 6 - 0
Tests/RunCMake/CMakePresets/IncludeCycle3Files.json.in

@@ -0,0 +1,6 @@
+{
+  "version": 4,
+  "include": [
+    "IncludeCycle3Files2.json"
+  ]
+}

+ 6 - 0
Tests/RunCMake/CMakePresets/IncludeCycle3Files2.json.in

@@ -0,0 +1,6 @@
+{
+  "version": 4,
+  "include": [
+    "IncludeCycle3Files3.json"
+  ]
+}

+ 6 - 0
Tests/RunCMake/CMakePresets/IncludeCycle3Files3.json.in

@@ -0,0 +1,6 @@
+{
+  "version": 4,
+  "include": [
+    "CMakePresets.json"
+  ]
+}

+ 3 - 0
Tests/RunCMake/CMakePresets/IncludeCycleUser.json.in

@@ -0,0 +1,3 @@
+{
+  "version": 3
+}

+ 1 - 0
Tests/RunCMake/CMakePresets/IncludeNotFound-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresets/IncludeNotFound-stderr.txt

@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/IncludeNotFound: File not found$

+ 11 - 0
Tests/RunCMake/CMakePresets/IncludeNotFound.json.in

@@ -0,0 +1,11 @@
+{
+  "version": 4,
+  "include": [
+    "NotFound.json"
+  ],
+  "configurePresets": [
+    {
+      "name": "IncludeNotFound"
+    }
+  ]
+}

+ 1 - 0
Tests/RunCMake/CMakePresets/IncludeOutsideProject-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresets/IncludeOutsideProject-stderr.txt

@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/IncludeOutsideProject: File included from outside project directory$

+ 11 - 0
Tests/RunCMake/CMakePresets/IncludeOutsideProject.json.in

@@ -0,0 +1,11 @@
+{
+  "version": 4,
+  "include": [
+    "IncludeOutsideProjectIntermediate.json"
+  ],
+  "configurePresets": [
+    {
+      "name": "IncludeOutsideProject"
+    }
+  ]
+}

+ 3 - 0
Tests/RunCMake/CMakePresets/IncludeOutsideProjectInclude.json

@@ -0,0 +1,3 @@
+{
+  "version": 4
+}

+ 6 - 0
Tests/RunCMake/CMakePresets/IncludeOutsideProjectIntermediate.json.in

@@ -0,0 +1,6 @@
+{
+  "version": 4,
+  "include": [
+    "@RunCMake_SOURCE_DIR@/IncludeOutsideProjectInclude.json"
+  ]
+}

+ 6 - 0
Tests/RunCMake/CMakePresets/IncludeOutsideProjectUser.json.in

@@ -0,0 +1,6 @@
+{
+  "version": 4,
+  "include": [
+    "IncludeOutsideProjectIntermediate.json"
+  ]
+}

+ 15 - 0
Tests/RunCMake/CMakePresets/IncludeUser.json.in

@@ -0,0 +1,15 @@
+{
+  "version": 4,
+  "include": [
+    "IncludeUserCommon.json"
+  ],
+  "configurePresets": [
+    {
+      "name": "IncludeUser",
+      "inherits": [
+        "Include",
+        "IncludeUserCommon"
+      ]
+    }
+  ]
+}

+ 8 - 0
Tests/RunCMake/CMakePresets/IncludeUserCommon.json.in

@@ -0,0 +1,8 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "IncludeUserCommon"
+    }
+  ]
+}

+ 0 - 0
Tests/RunCMake/CMakePresets/IncludeUserOutsideProject.cmake


+ 11 - 0
Tests/RunCMake/CMakePresets/IncludeUserOutsideProjectUser.json.in

@@ -0,0 +1,11 @@
+{
+  "version": 4,
+  "include": [
+    "@RunCMake_SOURCE_DIR@/IncludeOutsideProjectInclude.json"
+  ],
+  "configurePresets": [
+    {
+      "name": "IncludeUserOutsideProject"
+    }
+  ]
+}

+ 1 - 0
Tests/RunCMake/CMakePresets/IncludeV3-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresets/IncludeV3-stderr.txt

@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/IncludeV3: File version must be 4 or higher for include support$

+ 4 - 0
Tests/RunCMake/CMakePresets/IncludeV3.json.in

@@ -0,0 +1,4 @@
+{
+  "version": 3,
+  "include": []
+}

+ 1 - 0
Tests/RunCMake/CMakePresets/IncludeV4V3-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresets/IncludeV4V3-stderr.txt

@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/IncludeV4V3: File version must be 4 or higher for include support$

+ 6 - 0
Tests/RunCMake/CMakePresets/IncludeV4V3.json.in

@@ -0,0 +1,6 @@
+{
+  "version": 4,
+  "include": [
+    "IncludeV4V3Extra.json"
+  ]
+}

+ 4 - 0
Tests/RunCMake/CMakePresets/IncludeV4V3Extra.json.in

@@ -0,0 +1,4 @@
+{
+  "version": 3,
+  "include": []
+}

+ 45 - 0
Tests/RunCMake/CMakePresets/RunCMakeTest.cmake

@@ -44,6 +44,20 @@ function(run_cmake_presets name)
     configure_file("${CMakeUserPresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" @ONLY)
     configure_file("${CMakeUserPresets_FILE}" "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" @ONLY)
   endif()
   endif()
 
 
+  set(_CMakePresets_EXTRA_FILES_OUT)
+  set(_CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
+  foreach(_extra_file IN LISTS CMakePresets_EXTRA_FILES)
+    cmake_path(RELATIVE_PATH _extra_file
+      BASE_DIRECTORY "${RunCMake_SOURCE_DIR}"
+      OUTPUT_VARIABLE _extra_file_relative
+      )
+    string(REGEX REPLACE "\\.in$" "" _extra_file_out_relative "${_extra_file_relative}")
+    set(_extra_file_out "${RunCMake_TEST_SOURCE_DIR}/${_extra_file_out_relative}")
+    configure_file("${_extra_file}" "${_extra_file_out}")
+    list(APPEND _CMakePresets_EXTRA_FILES_OUT "${_extra_file_out}")
+    list(APPEND _CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS 0)
+  endforeach()
+
   set(_s_arg -S)
   set(_s_arg -S)
   if(CMakePresets_NO_S_ARG)
   if(CMakePresets_NO_S_ARG)
     set(_s_arg)
     set(_s_arg)
@@ -319,6 +333,37 @@ run_cmake_presets(OptionalBinaryDirFieldNoS)
 unset(CMakePresets_SOURCE_ARG)
 unset(CMakePresets_SOURCE_ARG)
 unset(CMakePresets_NO_S_ARG)
 unset(CMakePresets_NO_S_ARG)
 
 
+# Test include field
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_presets(IncludeV3)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+set(CMakePresets_EXTRA_FILES
+  "${RunCMake_SOURCE_DIR}/IncludeV4V3Extra.json.in"
+  )
+set(CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS 1)
+run_cmake_presets(IncludeV4V3)
+unset(CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
+set(CMakePresets_EXTRA_FILES
+  "${RunCMake_SOURCE_DIR}/IncludeCommon.json.in"
+  "${RunCMake_SOURCE_DIR}/IncludeUserCommon.json.in"
+  "${RunCMake_SOURCE_DIR}/subdir/CMakePresets.json.in"
+  )
+run_cmake_presets(Include --list-presets)
+unset(CMakePresets_EXTRA_FILES)
+run_cmake_presets(IncludeNotFound)
+run_cmake_presets(IncludeCycle)
+set(CMakePresets_EXTRA_FILES
+  "${RunCMake_SOURCE_DIR}/IncludeCycle3Files2.json.in"
+  "${RunCMake_SOURCE_DIR}/IncludeCycle3Files3.json.in"
+  )
+run_cmake_presets(IncludeCycle3Files)
+set(CMakePresets_EXTRA_FILES
+  "${RunCMake_SOURCE_DIR}/IncludeOutsideProjectIntermediate.json.in"
+  )
+run_cmake_presets(IncludeOutsideProject)
+unset(CMakePresets_EXTRA_FILES)
+run_cmake_presets(IncludeUserOutsideProject)
+
 # Test the example from the documentation
 # Test the example from the documentation
 file(READ "${RunCMake_SOURCE_DIR}/../../../Help/manual/presets/example.json" _example)
 file(READ "${RunCMake_SOURCE_DIR}/../../../Help/manual/presets/example.json" _example)
 string(REPLACE "\"generator\": \"Ninja\"" "\"generator\": \"@RunCMake_GENERATOR@\"" _example "${_example}")
 string(REPLACE "\"generator\": \"Ninja\"" "\"generator\": \"@RunCMake_GENERATOR@\"" _example "${_example}")

+ 7 - 0
Tests/RunCMake/CMakePresets/check.cmake

@@ -12,4 +12,11 @@ if(PYTHON_EXECUTABLE AND CMake_TEST_JSON_SCHEMA)
   if(EXISTS "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json")
   if(EXISTS "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json")
     validate_schema("${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" "${CMakeUserPresets_SCHEMA_EXPECTED_RESULT}")
     validate_schema("${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" "${CMakeUserPresets_SCHEMA_EXPECTED_RESULT}")
   endif()
   endif()
+
+  if(NOT CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
+    set(CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS "${_CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS}")
+  endif()
+  foreach(_f _r IN ZIP_LISTS _CMakePresets_EXTRA_FILES_OUT CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
+    validate_schema("${_f}" "${_r}")
+  endforeach()
 endif()
 endif()

+ 12 - 0
Tests/RunCMake/CMakePresets/subdir/CMakePresets.json.in

@@ -0,0 +1,12 @@
+{
+  "version": 4,
+  "include": [
+    "../IncludeCommon.json"
+  ],
+  "configurePresets": [
+    {
+      "name": "Subdir",
+      "inherits": "IncludeCommon"
+    }
+  ]
+}