Просмотр исходного кода

CMakePresets: Add include field

Fixes: #21331
Kyle Edwards 3 лет назад
Родитель
Сommit
26a5512c0f
42 измененных файлов с 351 добавлено и 7 удалено
  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
 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
-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
 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
 ``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
 ======
 
@@ -39,7 +55,7 @@ The root object recognizes the following fields:
 ``version``
 
   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``
 
@@ -82,6 +98,12 @@ The root object recognizes the following fields:
   An optional array of `Test Preset`_ objects.
   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
 ^^^^^^^^^^^^^^^^
 

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

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

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

@@ -42,6 +42,21 @@
         "testPresets": { "$ref": "#/definitions/testPresetsV3"}
       },
       "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": [
@@ -1235,6 +1250,13 @@
           "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:
       return "File version must be 2 or higher for build and test preset "
              "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:
       return "Invalid \"configurePreset\" field";
     case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED:
@@ -1010,6 +1014,8 @@ const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result)
              "support.";
     case ReadFileResult::CYCLIC_INCLUDE:
       return "Cyclic include among preset files";
+    case ReadFileResult::INCLUDE_OUTSIDE_PROJECT:
+      return "File included from outside project directory";
   }
 
   return "Unknown error";

+ 3 - 0
Source/cmCMakePresetsGraph.h

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

+ 57 - 3
Source/cmCMakePresetsGraphReadJSON.cxx

@@ -33,7 +33,7 @@ using TestPreset = cmCMakePresetsGraph::TestPreset;
 using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy;
 
 constexpr int MIN_VERSION = 1;
-constexpr int MAX_VERSION = 3;
+constexpr int MAX_VERSION = 4;
 
 struct CMakeVersion
 {
@@ -48,6 +48,7 @@ struct RootPresets
   std::vector<cmCMakePresetsGraph::ConfigurePreset> ConfigurePresets;
   std::vector<cmCMakePresetsGraph::BuildPreset> BuildPresets;
   std::vector<cmCMakePresetsGraph::TestPreset> TestPresets;
+  std::vector<std::string> Include;
 };
 
 std::unique_ptr<cmCMakePresetsGraphInternal::NotCondition> InvertCondition(
@@ -271,6 +272,13 @@ auto const CMakeVersionHelper =
     .Bind("minor"_s, &CMakeVersion::Minor, 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 =
   cmJSONObjectHelper<RootPresets, ReadFileResult>(
     ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
@@ -283,6 +291,7 @@ auto const RootPresetsHelper =
           cmCMakePresetsGraphInternal::TestPresetsHelper, false)
     .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
           CMakeVersionHelper, false)
+    .Bind("include"_s, &RootPresets::Include, IncludeVectorHelper, false)
     .Bind<std::nullptr_t>(
       "vendor"_s, nullptr,
       cmCMakePresetsGraphInternal::VendorHelper(ReadFileResult::INVALID_ROOT),
@@ -413,6 +422,19 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
   const std::string& filename, RootType rootType, ReadReason readReason,
   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) {
     if (cmSystemTools::SameFile(filename, f->Filename)) {
       file = f.get();
@@ -421,6 +443,22 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
       if (fileIt != inProgressFiles.end()) {
         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;
     }
   }
@@ -440,8 +478,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
   }
 
   int v = 0;
-  auto result = RootVersionHelper(v, &root);
-  if (result != ReadFileResult::READ_OK) {
+  if ((result = RootVersionHelper(v, &root)) != ReadFileResult::READ_OK) {
     return result;
   }
   if (v < MIN_VERSION || v > MAX_VERSION) {
@@ -454,6 +491,11 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
     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;
   if ((result = RootPresetsHelper(presets, &root)) !=
       ReadFileResult::READ_OK) {
@@ -571,6 +613,18 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
     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) {
     auto cmakePresetsFilename = GetFilename(this->SourceDir);
     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)
   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)
   if(CMakePresets_NO_S_ARG)
     set(_s_arg)
@@ -319,6 +333,37 @@ run_cmake_presets(OptionalBinaryDirFieldNoS)
 unset(CMakePresets_SOURCE_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
 file(READ "${RunCMake_SOURCE_DIR}/../../../Help/manual/presets/example.json" _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")
     validate_schema("${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" "${CMakeUserPresets_SCHEMA_EXPECTED_RESULT}")
   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()

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

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