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

Merge topic 'vs-package-restore'

9aa7831f05 Presets: add resolve packages setting to build presets.
b2f8f0bb87 cmGlobalVisualStudio10Generator: Auto restore NuGet packages.
193b8fca52 cmBuildOptions: Split build arguments into separate object.
6a10103493 Help: Update preset schema description for version 3 entries.

Acked-by: Kitware Robot <[email protected]>
Merge-request: !6761
Brad King 4 лет назад
Родитель
Сommit
63154cbf45
61 измененных файлов с 589 добавлено и 66 удалено
  1. 36 0
      Help/manual/cmake-presets.7.rst
  2. 1 0
      Help/manual/cmake-variables.7.rst
  3. 24 0
      Help/manual/cmake.1.rst
  4. 56 5
      Help/manual/presets/schema.json
  5. 13 0
      Help/release/dev/vs-package-restore.rst
  6. 22 0
      Help/variable/CMAKE_VS_NUGET_PACKAGE_RESTORE.rst
  7. 1 0
      Source/CMakeLists.txt
  8. 5 1
      Source/CTest/cmCTestBuildAndTestHandler.cxx
  9. 44 0
      Source/cmBuildOptions.h
  10. 3 0
      Source/cmCMakePresetsGraph.cxx
  11. 3 0
      Source/cmCMakePresetsGraph.h
  12. 34 1
      Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx
  13. 20 0
      Source/cmGeneratorTarget.cxx
  14. 3 0
      Source/cmGeneratorTarget.h
  15. 4 3
      Source/cmGlobalBorlandMakefileGenerator.cxx
  16. 2 1
      Source/cmGlobalBorlandMakefileGenerator.h
  17. 13 9
      Source/cmGlobalGenerator.cxx
  18. 5 3
      Source/cmGlobalGenerator.h
  19. 2 1
      Source/cmGlobalGhsMultiGenerator.cxx
  20. 3 1
      Source/cmGlobalGhsMultiGenerator.h
  21. 4 3
      Source/cmGlobalJOMMakefileGenerator.cxx
  22. 2 1
      Source/cmGlobalJOMMakefileGenerator.h
  23. 4 3
      Source/cmGlobalNMakeMakefileGenerator.cxx
  24. 2 1
      Source/cmGlobalNMakeMakefileGenerator.h
  25. 1 1
      Source/cmGlobalNinjaGenerator.cxx
  26. 3 1
      Source/cmGlobalNinjaGenerator.h
  27. 2 2
      Source/cmGlobalUnixMakefileGenerator3.cxx
  28. 3 1
      Source/cmGlobalUnixMakefileGenerator3.h
  29. 79 4
      Source/cmGlobalVisualStudio10Generator.cxx
  30. 4 1
      Source/cmGlobalVisualStudio10Generator.h
  31. 1 1
      Source/cmGlobalVisualStudio7Generator.cxx
  32. 2 1
      Source/cmGlobalVisualStudio7Generator.h
  33. 4 3
      Source/cmGlobalWatcomWMakeGenerator.cxx
  34. 3 1
      Source/cmGlobalWatcomWMakeGenerator.h
  35. 1 1
      Source/cmGlobalXCodeGenerator.cxx
  36. 2 1
      Source/cmGlobalXCodeGenerator.h
  37. 35 5
      Source/cmVisualStudio10TargetGenerator.cxx
  38. 1 0
      Source/cmVisualStudio10TargetGenerator.h
  39. 10 5
      Source/cmake.cxx
  40. 3 2
      Source/cmake.h
  41. 26 1
      Source/cmakemain.cxx
  42. 1 0
      Tests/RunCMake/CMakeLists.txt
  43. 7 1
      Tests/RunCMake/CMakePresetsBuild/Good.json.in
  44. 1 1
      Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
  45. 1 0
      Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-result.txt
  46. 1 0
      Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-stderr.txt
  47. 3 0
      Tests/RunCMake/VsNugetPackageRestore/CMakeLists.txt
  48. 17 0
      Tests/RunCMake/VsNugetPackageRestore/Package/CMakeLists.txt
  49. 9 0
      Tests/RunCMake/VsNugetPackageRestore/Package/Library.cs
  50. 14 0
      Tests/RunCMake/VsNugetPackageRestore/Program.cs
  51. 5 0
      Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/.nupkg.metadata
  52. BIN
      Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg
  53. 1 0
      Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg.sha512
  54. 11 0
      Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.nuspec
  55. 12 0
      Tests/RunCMake/VsNugetPackageRestore/RunCMakeTest.cmake
  56. 9 0
      Tests/RunCMake/VsNugetPackageRestore/VsNugetPackageRestore.cmake
  57. 7 0
      Tests/RunCMake/VsNugetPackageRestore/nuget.config.in
  58. 1 0
      Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-result.txt
  59. 1 0
      Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-stderr.txt
  60. 1 0
      Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-result.txt
  61. 1 0
      Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-stderr.txt

+ 36 - 0
Help/manual/cmake-presets.7.rst

@@ -474,6 +474,42 @@ that may contain the following fields:
   An optional bool. If true, equivalent to passing ``--clean-first`` on
   An optional bool. If true, equivalent to passing ``--clean-first`` on
   the command line.
   the command line.
 
 
+``resolvePackageReferences``
+
+  An optional string that specifies the package resolve mode. This is
+  allowed in preset files specifying version ``4`` or above.
+
+  This field overwrites the ``--resolve-package-references`` command line
+  parameter. If there are no targets that define package references, this
+  option does nothing. Valid values are:
+
+  ``on``
+
+    Causes package references to be resolved before attempting a build.
+
+  ``off``
+
+    Package references will not be resolved. Note that this may cause
+    errors in some build environments, such as .NET SDK style projects.
+
+  ``only``
+
+    Only resolve package references, but do not perform a build.
+
+  .. note::
+
+    If this setting is not specified in a preset, CMake will instead
+    use the setting specified by the ``--resolve-package-references``
+    command line parameter. If the command line parameter is not
+    provided either, an environment-specific cache variable will be
+    evaluated to decide, if package restoration should be performed.
+
+    When using the Visual Studio generator, package references are
+    defined using the :prop_tgt:`VS_PACKAGE_REFERENCES` property.
+    Package references are restored using NuGet. It can be disabled
+    by setting the ``CMAKE_VS_NUGET_PACKAGE_RESTORE`` variable to
+    ``OFF``. This can also be done from within a configure preset.
+
 ``verbose``
 ``verbose``
 
 
   An optional bool. If true, equivalent to passing ``--verbose`` on the
   An optional bool. If true, equivalent to passing ``--verbose`` on the

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -119,6 +119,7 @@ Variables that Provide Information
    /variable/CMAKE_VS_DEVENV_COMMAND
    /variable/CMAKE_VS_DEVENV_COMMAND
    /variable/CMAKE_VS_MSBUILD_COMMAND
    /variable/CMAKE_VS_MSBUILD_COMMAND
    /variable/CMAKE_VS_NsightTegra_VERSION
    /variable/CMAKE_VS_NsightTegra_VERSION
+   /variable/CMAKE_VS_NUGET_PACKAGE_RESTORE
    /variable/CMAKE_VS_PLATFORM_NAME
    /variable/CMAKE_VS_PLATFORM_NAME
    /variable/CMAKE_VS_PLATFORM_NAME_DEFAULT
    /variable/CMAKE_VS_PLATFORM_NAME_DEFAULT
    /variable/CMAKE_VS_PLATFORM_TOOLSET
    /variable/CMAKE_VS_PLATFORM_TOOLSET

+ 24 - 0
Help/manual/cmake.1.rst

@@ -463,6 +463,30 @@ following options:
   Build target ``clean`` first, then build.
   Build target ``clean`` first, then build.
   (To clean only, use ``--target clean``.)
   (To clean only, use ``--target clean``.)
 
 
+``--resolve-package-references=<on|off|only>``
+  .. versionadded:: 3.23
+
+  Resolve remote package references (e.g. NuGet packages) before build.
+  When set to ``on`` (default), packages will be restored before building a
+  target. When set to ``only``, the packages will be restored, but no build
+  will be performed. When set to ``off``, no packages will be restored.
+
+  If the target does not define any package references, this option does
+  nothing.
+
+  This setting can be specified in a build preset (using
+  ``resolvePackageReferences``). In this case, the command line option will
+  be ignored.
+
+  If the no command line parameter or preset option is not provided, an
+  environment-specific cache variable will be evaluated to decide, if package
+  restoration should be performed.
+
+  When using the Visual Studio generator, package references are defined
+  using the :prop_tgt:`VS_PACKAGE_REFERENCES` property. Package references
+  are restored using NuGet. It can be disabled by setting the
+  ``CMAKE_VS_NUGET_PACKAGE_RESTORE`` variable to ``OFF``.
+
 ``--use-stderr``
 ``--use-stderr``
   Ignored.  Behavior is default in CMake >= 3.0.
   Ignored.  Behavior is default in CMake >= 3.0.
 
 

+ 56 - 5
Help/manual/presets/schema.json

@@ -52,7 +52,7 @@
         "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
         "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
         "vendor": { "$ref": "#/definitions/vendor" },
         "vendor": { "$ref": "#/definitions/vendor" },
         "configurePresets": { "$ref": "#/definitions/configurePresetsV3"},
         "configurePresets": { "$ref": "#/definitions/configurePresetsV3"},
-        "buildPresets": { "$ref": "#/definitions/buildPresetsV3"},
+        "buildPresets": { "$ref": "#/definitions/buildPresetsV4"},
         "testPresets": { "$ref": "#/definitions/testPresetsV3"},
         "testPresets": { "$ref": "#/definitions/testPresetsV3"},
         "include": { "$ref": "#/definitions/include"}
         "include": { "$ref": "#/definitions/include"}
       },
       },
@@ -427,9 +427,25 @@
         "additionalProperties": false
         "additionalProperties": false
       }
       }
     },
     },
+    "buildPresetsItemsV4": {
+      "type": "array",
+      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 4 and higher.",
+      "items": {
+        "type": "object",
+        "properties": {
+          "resolvePackageReferences": {
+            "type": "string",
+            "description": "An optional string specifying the package resolve behavior. Valid values are \"on\" (packages are resolved prior to the build), \"off\" (packages are not resolved prior to the build), and \"only\" (packages are resolved, but no build will be performed).",
+            "enum": [
+              "on", "off", "only"
+            ]
+          }
+        }
+      }
+    },
     "buildPresetsItemsV3": {
     "buildPresetsItemsV3": {
       "type": "array",
       "type": "array",
-      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
+      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 3 and higher.",
       "items": {
       "items": {
         "type": "object",
         "type": "object",
         "properties": {
         "properties": {
@@ -558,9 +574,44 @@
         ]
         ]
       }
       }
     },
     },
+    "buildPresetsV4": {
+      "type": "array",
+      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 4 and higher.",
+      "allOf": [
+        { "$ref": "#/definitions/buildPresetsItemsV4" },
+        { "$ref": "#/definitions/buildPresetsItemsV3" },
+        { "$ref": "#/definitions/buildPresetsItemsV2" }
+      ],
+      "items": {
+        "type": "object",
+        "properties": {
+          "name": {},
+          "hidden": {},
+          "inherits": {},
+          "configurePreset": {},
+          "vendor": {},
+          "displayName": {},
+          "description": {},
+          "inheritConfigureEnvironment": {},
+          "environment": {},
+          "jobs": {},
+          "targets": {},
+          "configuration": {},
+          "cleanFirst": {},
+          "resolvePackageReferences": {},
+          "verbose": {},
+          "nativeToolOptions": {},
+          "condition": {}
+        },
+        "required": [
+          "name"
+        ],
+        "additionalProperties": false
+      }
+    },
     "buildPresetsV3": {
     "buildPresetsV3": {
       "type": "array",
       "type": "array",
-      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
+      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 3 and higher.",
       "allOf": [
       "allOf": [
         { "$ref": "#/definitions/buildPresetsItemsV3" },
         { "$ref": "#/definitions/buildPresetsItemsV3" },
         { "$ref": "#/definitions/buildPresetsItemsV2" }
         { "$ref": "#/definitions/buildPresetsItemsV2" }
@@ -624,7 +675,7 @@
     },
     },
     "testPresetsItemsV3": {
     "testPresetsItemsV3": {
       "type": "array",
       "type": "array",
-      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
+      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 3 and higher.",
       "items": {
       "items": {
         "type": "object",
         "type": "object",
         "properties": {
         "properties": {
@@ -949,7 +1000,7 @@
     },
     },
     "testPresetsV3": {
     "testPresetsV3": {
       "type": "array",
       "type": "array",
-      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
+      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 3 and higher.",
       "allOf": [
       "allOf": [
         { "$ref": "#/definitions/testPresetsItemsV2" },
         { "$ref": "#/definitions/testPresetsItemsV2" },
         { "$ref": "#/definitions/testPresetsItemsV3" }
         { "$ref": "#/definitions/testPresetsItemsV3" }

+ 13 - 0
Help/release/dev/vs-package-restore.rst

@@ -0,0 +1,13 @@
+vs-package-restore
+------------------
+
+* Targets with :prop_tgt:`VS_PACKAGE_REFERENCES` will now automatically attempt
+  to restore the package references from NuGet. The cache variable
+  :variable:`CMAKE_VS_NUGET_PACKAGE_RESTORE` was added to toggle automatic
+  package restore off.
+
+* :manual:`cmake(1)` gained the ``--resolve-package-references=<on|off|only>``
+  command-line option to control automatic package restoration.
+
+* :manual:`cmake-presets(7)` gained support for specifying the
+  ``resolvePackageReferences`` command line option in a build preset.

+ 22 - 0
Help/variable/CMAKE_VS_NUGET_PACKAGE_RESTORE.rst

@@ -0,0 +1,22 @@
+CMAKE_VS_NUGET_PACKAGE_RESTORE
+------------------------------
+
+.. versionadded:: 3.23
+
+When using a Visual Studio generator, this cache variable controls
+if msbuild should automatically attempt to restore NuGet packages
+prior to a build. NuGet packages can be defined using the
+:prop_tgt:`VS_PACKAGE_REFERENCES` property on a target. If no
+package references are defined, this setting will do nothing.
+
+The command line option ``--resolve-package-references`` can be used
+alternatively to control the resolve behavior globally. This option
+will take precedence over the cache variable.
+
+Targets that use the :prop_tgt:`DOTNET_SDK` are required to run a
+restore before building. Disabling this option may cause the build
+to fail in such projects.
+
+This setting is stored as a cache entry. Default value is ``ON``.
+
+See also the :prop_tgt:`VS_PACKAGE_REFERENCES` property.

+ 1 - 0
Source/CMakeLists.txt

@@ -155,6 +155,7 @@ set(SRCS
   cmBinUtilsWindowsPELinker.h
   cmBinUtilsWindowsPELinker.h
   cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
   cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
   cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
   cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
+  cmBuildOptions.h
   cmCacheManager.cxx
   cmCacheManager.cxx
   cmCacheManager.h
   cmCacheManager.h
   cmCLocaleEnvironmentScope.h
   cmCLocaleEnvironmentScope.h

+ 5 - 1
Source/CTest/cmCTestBuildAndTestHandler.cxx

@@ -9,6 +9,7 @@
 
 
 #include "cmsys/Process.h"
 #include "cmsys/Process.h"
 
 
+#include "cmBuildOptions.h"
 #include "cmCTest.h"
 #include "cmCTest.h"
 #include "cmCTestTestHandler.h"
 #include "cmCTestTestHandler.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGenerator.h"
@@ -263,10 +264,13 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
     if (!config) {
     if (!config) {
       config = "Debug";
       config = "Debug";
     }
     }
+
+    cmBuildOptions buildOptions(!this->BuildNoClean, false,
+                                PackageResolveMode::Disable);
     int retVal = cm.GetGlobalGenerator()->Build(
     int retVal = cm.GetGlobalGenerator()->Build(
       cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir,
       cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir,
       this->BuildProject, { tar }, output, this->BuildMakeProgram, config,
       this->BuildProject, { tar }, output, this->BuildMakeProgram, config,
-      !this->BuildNoClean, false, false, remainingTime);
+      buildOptions, false, remainingTime);
     out << output;
     out << output;
     // if the build failed then return
     // if the build failed then return
     if (retVal) {
     if (retVal) {

+ 44 - 0
Source/cmBuildOptions.h

@@ -0,0 +1,44 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+/** \brief Defines how to resolve packages **/
+enum class PackageResolveMode
+{
+  /** \brief Defines behavior based on cache variable (e.g.
+     CMAKE_VS_NUGET_PACKAGE_RESTORE). This is the default. **/
+  FromCacheVariable,
+
+  /** \brief Ignore behavior defined by cache variable and forces packages to
+     be resolved prior to build. **/
+  Force,
+
+  /** \brief Ignore behavior defined by cache variable and forces packages to
+     be resolved, but skip the actual build. **/
+  OnlyResolve,
+
+  /** \brief Ignore behavior defined by cache variable and dont resolve any
+     packages **/
+  Disable
+};
+
+struct cmBuildOptions
+{
+public:
+  cmBuildOptions() noexcept = default;
+  explicit cmBuildOptions(bool clean, bool fast,
+                          PackageResolveMode resolveMode) noexcept
+    : Clean(clean)
+    , Fast(fast)
+    , ResolveMode(resolveMode)
+  {
+  }
+  explicit cmBuildOptions(const cmBuildOptions&) noexcept = default;
+  cmBuildOptions& operator=(const cmBuildOptions&) noexcept = default;
+
+  bool Clean = false;
+  bool Fast = false;
+  PackageResolveMode ResolveMode = PackageResolveMode::FromCacheVariable;
+};

+ 3 - 0
Source/cmCMakePresetsGraph.cxx

@@ -724,6 +724,9 @@ cmCMakePresetsGraph::BuildPreset::VisitPresetInherit(
   InheritOptionalValue(preset.CleanFirst, parent.CleanFirst);
   InheritOptionalValue(preset.CleanFirst, parent.CleanFirst);
   InheritOptionalValue(preset.Verbose, parent.Verbose);
   InheritOptionalValue(preset.Verbose, parent.Verbose);
   InheritVector(preset.NativeToolOptions, parent.NativeToolOptions);
   InheritVector(preset.NativeToolOptions, parent.NativeToolOptions);
+  if (!preset.ResolvePackageReferences) {
+    preset.ResolvePackageReferences = parent.ResolvePackageReferences;
+  }
 
 
   return ReadFileResult::READ_OK;
   return ReadFileResult::READ_OK;
 }
 }

+ 3 - 0
Source/cmCMakePresetsGraph.h

@@ -14,6 +14,8 @@
 
 
 #include <cm/optional>
 #include <cm/optional>
 
 
+enum class PackageResolveMode;
+
 class cmCMakePresetsGraph
 class cmCMakePresetsGraph
 {
 {
 public:
 public:
@@ -181,6 +183,7 @@ public:
     cm::optional<bool> CleanFirst;
     cm::optional<bool> CleanFirst;
     cm::optional<bool> Verbose;
     cm::optional<bool> Verbose;
     std::vector<std::string> NativeToolOptions;
     std::vector<std::string> NativeToolOptions;
+    cm::optional<PackageResolveMode> ResolvePackageReferences;
 
 
     ReadFileResult VisitPresetInherit(const Preset& parent) override;
     ReadFileResult VisitPresetInherit(const Preset& parent) override;
     ReadFileResult VisitPresetAfterInherit(int /* version */) override;
     ReadFileResult VisitPresetAfterInherit(int /* version */) override;

+ 34 - 1
Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx

@@ -12,6 +12,7 @@
 
 
 #include <cm3p/json/value.h>
 #include <cm3p/json/value.h>
 
 
+#include "cmBuildOptions.h"
 #include "cmCMakePresetsGraph.h"
 #include "cmCMakePresetsGraph.h"
 #include "cmCMakePresetsGraphInternal.h"
 #include "cmCMakePresetsGraphInternal.h"
 #include "cmJSONHelpers.h"
 #include "cmJSONHelpers.h"
@@ -20,6 +21,37 @@ namespace {
 using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
 using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
 using BuildPreset = cmCMakePresetsGraph::BuildPreset;
 using BuildPreset = cmCMakePresetsGraph::BuildPreset;
 
 
+ReadFileResult PackageResolveModeHelper(cm::optional<PackageResolveMode>& out,
+                                        const Json::Value* value)
+{
+  if (!value) {
+    out = cm::nullopt;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "on") {
+    out = PackageResolveMode::Force;
+  } else if (value->asString() == "off") {
+    out = PackageResolveMode::Disable;
+  } else if (value->asString() == "only") {
+    out = PackageResolveMode::OnlyResolve;
+  } else {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  return ReadFileResult::READ_OK;
+}
+
+std::function<ReadFileResult(BuildPreset&, const Json::Value*)> const
+  ResolvePackageReferencesHelper =
+    [](BuildPreset& out, const Json::Value* value) -> ReadFileResult {
+  return PackageResolveModeHelper(out.ResolvePackageReferences, value);
+};
+
 auto const BuildPresetHelper =
 auto const BuildPresetHelper =
   cmJSONObjectHelper<BuildPreset, ReadFileResult>(
   cmJSONObjectHelper<BuildPreset, ReadFileResult>(
     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
     ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
@@ -59,7 +91,8 @@ auto const BuildPresetHelper =
     .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
     .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
           cmCMakePresetsGraphInternal::PresetVectorStringHelper, false)
           cmCMakePresetsGraphInternal::PresetVectorStringHelper, false)
     .Bind("condition"_s, &BuildPreset::ConditionEvaluator,
     .Bind("condition"_s, &BuildPreset::ConditionEvaluator,
-          cmCMakePresetsGraphInternal::PresetConditionHelper, false);
+          cmCMakePresetsGraphInternal::PresetConditionHelper, false)
+    .Bind("resolvePackageReferences"_s, ResolvePackageReferencesHelper, false);
 }
 }
 
 
 namespace cmCMakePresetsGraphInternal {
 namespace cmCMakePresetsGraphInternal {

+ 20 - 0
Source/cmGeneratorTarget.cxx

@@ -8102,6 +8102,26 @@ cmLinkItem cmGeneratorTarget::ResolveLinkItem(BT<std::string> const& name,
   return cmLinkItem(resolved.Target, false, bt);
   return cmLinkItem(resolved.Target, false, bt);
 }
 }
 
 
+bool cmGeneratorTarget::HasPackageReferences() const
+{
+  return this->IsInBuildSystem() &&
+    !this->GetProperty("VS_PACKAGE_REFERENCES")->empty();
+}
+
+std::vector<std::string> cmGeneratorTarget::GetPackageReferences() const
+{
+  std::vector<std::string> packageReferences;
+
+  if (this->IsInBuildSystem()) {
+    if (cmValue vsPackageReferences =
+          this->GetProperty("VS_PACKAGE_REFERENCES")) {
+      cmExpandList(*vsPackageReferences, packageReferences);
+    }
+  }
+
+  return packageReferences;
+}
+
 std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const
 std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const
 {
 {
   if (OutputInfo const* info = this->GetOutputInfo(config)) {
   if (OutputInfo const* info = this->GetOutputInfo(config)) {

+ 3 - 0
Source/cmGeneratorTarget.h

@@ -424,6 +424,9 @@ public:
   cmLinkItem ResolveLinkItem(BT<std::string> const& name,
   cmLinkItem ResolveLinkItem(BT<std::string> const& name,
                              cmLocalGenerator const* lg) const;
                              cmLocalGenerator const* lg) const;
 
 
+  bool HasPackageReferences() const;
+  std::vector<std::string> GetPackageReferences() const;
+
   // Compute the set of languages compiled by the target.  This is
   // Compute the set of languages compiled by the target.  This is
   // computed every time it is called because the languages can change
   // computed every time it is called because the languages can change
   // when source file properties are changed and we do not have enough
   // when source file properties are changed and we do not have enough

+ 4 - 3
Source/cmGlobalBorlandMakefileGenerator.cxx

@@ -71,12 +71,13 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
 cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
 cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& projectName,
   const std::string& makeProgram, const std::string& projectName,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
-  const std::string& config, bool fast, int /*jobs*/, bool verbose,
+  const std::string& config, int /*jobs*/, bool verbose,
+  const cmBuildOptions& buildOptions,
   std::vector<std::string> const& makeOptions)
   std::vector<std::string> const& makeOptions)
 {
 {
   return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
   return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
-    makeProgram, projectName, projectDir, targetNames, config, fast,
-    cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
+    makeProgram, projectName, projectDir, targetNames, config,
+    cmake::NO_BUILD_PARALLEL_LEVEL, verbose, buildOptions, makeOptions);
 }
 }
 
 
 void cmGlobalBorlandMakefileGenerator::PrintBuildCommandAdvice(
 void cmGlobalBorlandMakefileGenerator::PrintBuildCommandAdvice(

+ 2 - 1
Source/cmGlobalBorlandMakefileGenerator.h

@@ -59,7 +59,8 @@ protected:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
-    const std::string& config, bool fast, int jobs, bool verbose,
+    const std::string& config, int jobs, bool verbose,
+    const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
       std::vector<std::string>()) override;
 
 

+ 13 - 9
Source/cmGlobalGenerator.cxx

@@ -1994,16 +1994,19 @@ int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
   }
   }
   std::string config =
   std::string config =
     mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
     mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
+  cmBuildOptions defaultBuildOptions(false, fast, PackageResolveMode::Disable);
+
   return this->Build(jobs, srcdir, bindir, projectName, newTarget, output, "",
   return this->Build(jobs, srcdir, bindir, projectName, newTarget, output, "",
-                     config, false, fast, false, this->TryCompileTimeout);
+                     config, defaultBuildOptions, false,
+                     this->TryCompileTimeout);
 }
 }
 
 
 std::vector<cmGlobalGenerator::GeneratedMakeCommand>
 std::vector<cmGlobalGenerator::GeneratedMakeCommand>
 cmGlobalGenerator::GenerateBuildCommand(
 cmGlobalGenerator::GenerateBuildCommand(
   const std::string& /*unused*/, const std::string& /*unused*/,
   const std::string& /*unused*/, const std::string& /*unused*/,
   const std::string& /*unused*/, std::vector<std::string> const& /*unused*/,
   const std::string& /*unused*/, std::vector<std::string> const& /*unused*/,
-  const std::string& /*unused*/, bool /*unused*/, int /*unused*/,
-  bool /*unused*/, std::vector<std::string> const& /*unused*/)
+  const std::string& /*unused*/, int /*unused*/, bool /*unused*/,
+  const cmBuildOptions& /*unused*/, std::vector<std::string> const& /*unused*/)
 {
 {
   GeneratedMakeCommand makeCommand;
   GeneratedMakeCommand makeCommand;
   makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
   makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
@@ -2021,7 +2024,7 @@ int cmGlobalGenerator::Build(
   int jobs, const std::string& /*unused*/, const std::string& bindir,
   int jobs, const std::string& /*unused*/, const std::string& bindir,
   const std::string& projectName, const std::vector<std::string>& targets,
   const std::string& projectName, const std::vector<std::string>& targets,
   std::string& output, const std::string& makeCommandCSTR,
   std::string& output, const std::string& makeCommandCSTR,
-  const std::string& config, bool clean, bool fast, bool verbose,
+  const std::string& config, const cmBuildOptions& buildOptions, bool verbose,
   cmDuration timeout, cmSystemTools::OutputOption outputflag,
   cmDuration timeout, cmSystemTools::OutputOption outputflag,
   std::vector<std::string> const& nativeOptions)
   std::vector<std::string> const& nativeOptions)
 {
 {
@@ -2053,9 +2056,9 @@ int cmGlobalGenerator::Build(
   std::string outputBuffer;
   std::string outputBuffer;
   std::string* outputPtr = &outputBuffer;
   std::string* outputPtr = &outputBuffer;
 
 
-  std::vector<GeneratedMakeCommand> makeCommand =
-    this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, targets,
-                               realConfig, fast, jobs, verbose, nativeOptions);
+  std::vector<GeneratedMakeCommand> makeCommand = this->GenerateBuildCommand(
+    makeCommandCSTR, projectName, bindir, targets, realConfig, jobs, verbose,
+    buildOptions, nativeOptions);
 
 
   // Workaround to convince some commands to produce output.
   // Workaround to convince some commands to produce output.
   if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
   if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
@@ -2064,10 +2067,11 @@ int cmGlobalGenerator::Build(
   }
   }
 
 
   // should we do a clean first?
   // should we do a clean first?
-  if (clean) {
+  if (buildOptions.Clean) {
     std::vector<GeneratedMakeCommand> cleanCommand =
     std::vector<GeneratedMakeCommand> cleanCommand =
       this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir,
       this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir,
-                                 { "clean" }, realConfig, fast, jobs, verbose);
+                                 { "clean" }, realConfig, jobs, verbose,
+                                 buildOptions);
     output += "\nRun Clean Command:";
     output += "\nRun Clean Command:";
     output += cleanCommand.front().Printable();
     output += cleanCommand.front().Printable();
     output += "\n";
     output += "\n";

+ 5 - 3
Source/cmGlobalGenerator.h

@@ -20,6 +20,7 @@
 
 
 #include "cm_codecvt.hxx"
 #include "cm_codecvt.hxx"
 
 
+#include "cmBuildOptions.h"
 #include "cmCustomCommandLines.h"
 #include "cmCustomCommandLines.h"
 #include "cmDuration.h"
 #include "cmDuration.h"
 #include "cmExportSet.h"
 #include "cmExportSet.h"
@@ -229,8 +230,8 @@ public:
     int jobs, const std::string& srcdir, const std::string& bindir,
     int jobs, const std::string& srcdir, const std::string& bindir,
     const std::string& projectName,
     const std::string& projectName,
     std::vector<std::string> const& targetNames, std::string& output,
     std::vector<std::string> const& targetNames, std::string& output,
-    const std::string& makeProgram, const std::string& config, bool clean,
-    bool fast, bool verbose, cmDuration timeout,
+    const std::string& makeProgram, const std::string& config,
+    const cmBuildOptions& buildOptions, bool verbose, cmDuration timeout,
     cmSystemTools::OutputOption outputflag = cmSystemTools::OUTPUT_NONE,
     cmSystemTools::OutputOption outputflag = cmSystemTools::OUTPUT_NONE,
     std::vector<std::string> const& nativeOptions =
     std::vector<std::string> const& nativeOptions =
       std::vector<std::string>());
       std::vector<std::string>());
@@ -248,7 +249,8 @@ public:
   virtual std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   virtual std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
-    const std::string& config, bool fast, int jobs, bool verbose,
+    const std::string& config, int jobs, bool verbose,
+    const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions = std::vector<std::string>());
     std::vector<std::string> const& makeOptions = std::vector<std::string>());
 
 
   virtual void PrintBuildCommandAdvice(std::ostream& os, int jobs) const;
   virtual void PrintBuildCommandAdvice(std::ostream& os, int jobs) const;

+ 2 - 1
Source/cmGlobalGhsMultiGenerator.cxx

@@ -510,7 +510,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
 cmGlobalGhsMultiGenerator::GenerateBuildCommand(
 cmGlobalGhsMultiGenerator::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& projectName,
   const std::string& makeProgram, const std::string& projectName,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
-  const std::string& /*config*/, bool /*fast*/, int jobs, bool /*verbose*/,
+  const std::string& /*config*/, int jobs, bool /*verbose*/,
+  const cmBuildOptions& /*buildOptions*/,
   std::vector<std::string> const& makeOptions)
   std::vector<std::string> const& makeOptions)
 {
 {
   GeneratedMakeCommand makeCommand = {};
   GeneratedMakeCommand makeCommand = {};

+ 3 - 1
Source/cmGlobalGhsMultiGenerator.h

@@ -9,6 +9,7 @@
 #include <utility>
 #include <utility>
 #include <vector>
 #include <vector>
 
 
+#include "cmBuildOptions.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGeneratorFactory.h"
 #include "cmGlobalGeneratorFactory.h"
 #include "cmTargetDepend.h"
 #include "cmTargetDepend.h"
@@ -87,7 +88,8 @@ protected:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
-    const std::string& config, bool fast, int jobs, bool verbose,
+    const std::string& config, int jobs, bool verbose,
+    const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
       std::vector<std::string>()) override;
 
 

+ 4 - 3
Source/cmGlobalJOMMakefileGenerator.cxx

@@ -63,7 +63,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
 cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
 cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& projectName,
   const std::string& makeProgram, const std::string& projectName,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
-  const std::string& config, bool fast, int jobs, bool verbose,
+  const std::string& config, int jobs, bool verbose,
+  const cmBuildOptions& buildOptions,
   std::vector<std::string> const& makeOptions)
   std::vector<std::string> const& makeOptions)
 {
 {
   std::vector<std::string> jomMakeOptions;
   std::vector<std::string> jomMakeOptions;
@@ -81,6 +82,6 @@ cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
   }
   }
 
 
   return cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
   return cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
-    makeProgram, projectName, projectDir, targetNames, config, fast, jobs,
-    verbose, jomMakeOptions);
+    makeProgram, projectName, projectDir, targetNames, config, jobs, verbose,
+    buildOptions, jomMakeOptions);
 }
 }

+ 2 - 1
Source/cmGlobalJOMMakefileGenerator.h

@@ -52,7 +52,8 @@ protected:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
-    const std::string& config, bool fast, int jobs, bool verbose,
+    const std::string& config, int jobs, bool verbose,
+    const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
       std::vector<std::string>()) override;
 
 

+ 4 - 3
Source/cmGlobalNMakeMakefileGenerator.cxx

@@ -106,7 +106,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
 cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
 cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& projectName,
   const std::string& makeProgram, const std::string& projectName,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
-  const std::string& config, bool fast, int /*jobs*/, bool verbose,
+  const std::string& config, int /*jobs*/, bool verbose,
+  const cmBuildOptions& buildOptions,
   std::vector<std::string> const& makeOptions)
   std::vector<std::string> const& makeOptions)
 {
 {
   std::vector<std::string> nmakeMakeOptions;
   std::vector<std::string> nmakeMakeOptions;
@@ -117,8 +118,8 @@ cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
   cm::append(nmakeMakeOptions, makeOptions);
   cm::append(nmakeMakeOptions, makeOptions);
 
 
   return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
   return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
-    makeProgram, projectName, projectDir, targetNames, config, fast,
-    cmake::NO_BUILD_PARALLEL_LEVEL, verbose, nmakeMakeOptions);
+    makeProgram, projectName, projectDir, targetNames, config,
+    cmake::NO_BUILD_PARALLEL_LEVEL, verbose, buildOptions, nmakeMakeOptions);
 }
 }
 
 
 void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os,
 void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os,

+ 2 - 1
Source/cmGlobalNMakeMakefileGenerator.h

@@ -58,7 +58,8 @@ protected:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
-    const std::string& config, bool fast, int jobs, bool verbose,
+    const std::string& config, int jobs, bool verbose,
+    const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
       std::vector<std::string>()) override;
 
 

+ 1 - 1
Source/cmGlobalNinjaGenerator.cxx

@@ -955,7 +955,7 @@ cmGlobalNinjaGenerator::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& /*projectName*/,
   const std::string& makeProgram, const std::string& /*projectName*/,
   const std::string& /*projectDir*/,
   const std::string& /*projectDir*/,
   std::vector<std::string> const& targetNames, const std::string& config,
   std::vector<std::string> const& targetNames, const std::string& config,
-  bool /*fast*/, int jobs, bool verbose,
+  int jobs, bool verbose, const cmBuildOptions& /*buildOptions*/,
   std::vector<std::string> const& makeOptions)
   std::vector<std::string> const& makeOptions)
 {
 {
   GeneratedMakeCommand makeCommand;
   GeneratedMakeCommand makeCommand;

+ 3 - 1
Source/cmGlobalNinjaGenerator.h

@@ -18,6 +18,7 @@
 
 
 #include "cm_codecvt.hxx"
 #include "cm_codecvt.hxx"
 
 
+#include "cmBuildOptions.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalCommonGenerator.h"
 #include "cmGlobalCommonGenerator.h"
 #include "cmGlobalGeneratorFactory.h"
 #include "cmGlobalGeneratorFactory.h"
@@ -199,7 +200,8 @@ public:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
-    const std::string& config, bool fast, int jobs, bool verbose,
+    const std::string& config, int jobs, bool verbose,
+    const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
       std::vector<std::string>()) override;
 
 

+ 2 - 2
Source/cmGlobalUnixMakefileGenerator3.cxx

@@ -518,7 +518,7 @@ cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& /*projectName*/,
   const std::string& makeProgram, const std::string& /*projectName*/,
   const std::string& /*projectDir*/,
   const std::string& /*projectDir*/,
   std::vector<std::string> const& targetNames, const std::string& /*config*/,
   std::vector<std::string> const& targetNames, const std::string& /*config*/,
-  bool fast, int jobs, bool verbose,
+  int jobs, bool verbose, const cmBuildOptions& buildOptions,
   std::vector<std::string> const& makeOptions)
   std::vector<std::string> const& makeOptions)
 {
 {
   GeneratedMakeCommand makeCommand;
   GeneratedMakeCommand makeCommand;
@@ -548,7 +548,7 @@ cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
   makeCommand.Add(makeOptions.begin(), makeOptions.end());
   makeCommand.Add(makeOptions.begin(), makeOptions.end());
   for (auto tname : targetNames) {
   for (auto tname : targetNames) {
     if (!tname.empty()) {
     if (!tname.empty()) {
-      if (fast) {
+      if (buildOptions.Fast) {
         tname += "/fast";
         tname += "/fast";
       }
       }
       cmSystemTools::ConvertToOutputSlashes(tname);
       cmSystemTools::ConvertToOutputSlashes(tname);

+ 3 - 1
Source/cmGlobalUnixMakefileGenerator3.h

@@ -12,6 +12,7 @@
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
 
 
+#include "cmBuildOptions.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalCommonGenerator.h"
 #include "cmGlobalCommonGenerator.h"
 #include "cmGlobalGeneratorFactory.h"
 #include "cmGlobalGeneratorFactory.h"
@@ -163,7 +164,8 @@ public:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
-    const std::string& config, bool fast, int jobs, bool verbose,
+    const std::string& config, int jobs, bool verbose,
+    const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
       std::vector<std::string>()) override;
 
 

+ 79 - 4
Source/cmGlobalVisualStudio10Generator.cxx

@@ -724,6 +724,10 @@ void cmGlobalVisualStudio10Generator::Generate()
     /* clang-format on */
     /* clang-format on */
     lg->IssueMessage(MessageType::WARNING, e.str());
     lg->IssueMessage(MessageType::WARNING, e.str());
   }
   }
+  if (cmValue cached = this->CMakeInstance->GetState()->GetCacheEntryValue(
+        "CMAKE_VS_NUGET_PACKAGE_RESTORE")) {
+    this->CMakeInstance->MarkCliAsUsed("CMAKE_VS_NUGET_PACKAGE_RESTORE");
+  }
 }
 }
 
 
 void cmGlobalVisualStudio10Generator::EnableLanguage(
 void cmGlobalVisualStudio10Generator::EnableLanguage(
@@ -1099,7 +1103,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
 cmGlobalVisualStudio10Generator::GenerateBuildCommand(
 cmGlobalVisualStudio10Generator::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& projectName,
   const std::string& makeProgram, const std::string& projectName,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
-  const std::string& config, bool fast, int jobs, bool verbose,
+  const std::string& config, int jobs, bool verbose,
+  const cmBuildOptions& buildOptions,
   std::vector<std::string> const& makeOptions)
   std::vector<std::string> const& makeOptions)
 {
 {
   std::vector<GeneratedMakeCommand> makeCommands;
   std::vector<GeneratedMakeCommand> makeCommands;
@@ -1145,8 +1150,8 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand(
   if (useDevEnv) {
   if (useDevEnv) {
     // Use devenv to build solutions containing Intel Fortran projects.
     // Use devenv to build solutions containing Intel Fortran projects.
     return cmGlobalVisualStudio7Generator::GenerateBuildCommand(
     return cmGlobalVisualStudio7Generator::GenerateBuildCommand(
-      makeProgram, projectName, projectDir, targetNames, config, fast, jobs,
-      verbose, makeOptions);
+      makeProgram, projectName, projectDir, targetNames, config, jobs, verbose,
+      buildOptions, makeOptions);
   }
   }
 
 
   std::vector<std::string> realTargetNames = targetNames;
   std::vector<std::string> realTargetNames = targetNames;
@@ -1178,8 +1183,66 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand(
           cmSystemTools::ConvertToUnixSlashes(targetProject);
           cmSystemTools::ConvertToUnixSlashes(targetProject);
         }
         }
       }
       }
-      makeCommand.Add(std::move(targetProject));
+      makeCommand.Add(targetProject);
+
+      // Check if we do need a restore at all (i.e. if there are package
+      // references and restore has not been disabled by a command line option.
+      PackageResolveMode restoreMode = buildOptions.ResolveMode;
+      bool requiresRestore = true;
+
+      if (restoreMode == PackageResolveMode::Disable) {
+        requiresRestore = false;
+      } else if (cmValue cached =
+                   this->CMakeInstance->GetState()->GetCacheEntryValue(
+                     tname + "_REQUIRES_VS_PACKAGE_RESTORE")) {
+        requiresRestore = cached.IsOn();
+      } else {
+        // There are no package references defined.
+        requiresRestore = false;
+      }
+
+      // If a restore is required, evaluate the restore mode.
+      if (requiresRestore) {
+        if (restoreMode == PackageResolveMode::OnlyResolve) {
+          // Only invoke the restore target on the project.
+          makeCommand.Add("/t:Restore");
+        } else {
+          // Invoke restore target, unless it has been explicitly disabled.
+          bool restorePackages = true;
+
+          if (this->Version < VS15) {
+            // Package restore is only supported starting from Visual Studio
+            // 2017. Package restore must be executed manually using NuGet
+            // shell for older versions.
+            this->CMakeInstance->IssueMessage(
+              MessageType::WARNING,
+              "Restoring package references is only supported for Visual "
+              "Studio 2017 and later. You have to manually restore the "
+              "packages using NuGet before building the project.");
+            restorePackages = false;
+          } else if (restoreMode == PackageResolveMode::FromCacheVariable) {
+            // Decide if a restore is performed, based on a cache variable.
+            if (cmValue cached =
+                  this->CMakeInstance->GetState()->GetCacheEntryValue(
+                    "CMAKE_VS_NUGET_PACKAGE_RESTORE"))
+              restorePackages = cached.IsOn();
+          }
+
+          if (restorePackages) {
+            if (this->IsMsBuildRestoreSupported()) {
+              makeCommand.Add("/restore");
+            } else {
+              GeneratedMakeCommand restoreCommand;
+              restoreCommand.Add(makeProgramSelected);
+              restoreCommand.Add(targetProject);
+              restoreCommand.Add("/t:Restore");
+              makeCommands.emplace_back(restoreCommand);
+            }
+          }
+        }
+      }
     }
     }
+
     std::string configArg = "/p:Configuration=";
     std::string configArg = "/p:Configuration=";
     if (!config.empty()) {
     if (!config.empty()) {
       configArg += config;
       configArg += config;
@@ -1559,6 +1622,18 @@ cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetNasmFlagTable() const
   return LoadFlagTable(std::string(), this->DefaultNasmFlagTableName, "NASM");
   return LoadFlagTable(std::string(), this->DefaultNasmFlagTableName, "NASM");
 }
 }
 
 
+bool cmGlobalVisualStudio10Generator::IsMsBuildRestoreSupported() const
+{
+  if (this->Version >= VS16) {
+    return true;
+  }
+
+  static std::string const vsVer15_7_5 = "15.7.27703.2042";
+  cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
+  return (vsVer &&
+          cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer15_7_5));
+}
+
 std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const
 std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const
 {
 {
   std::string const& toolset = this->GetPlatformToolsetString();
   std::string const& toolset = this->GetPlatformToolsetString();

+ 4 - 1
Source/cmGlobalVisualStudio10Generator.h

@@ -43,7 +43,8 @@ public:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
-    const std::string& config, bool fast, int jobs, bool verbose,
+    const std::string& config, int jobs, bool verbose,
+    const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
       std::vector<std::string>()) override;
 
 
@@ -172,6 +173,8 @@ public:
   cmIDEFlagTable const* GetMasmFlagTable() const;
   cmIDEFlagTable const* GetMasmFlagTable() const;
   cmIDEFlagTable const* GetNasmFlagTable() const;
   cmIDEFlagTable const* GetNasmFlagTable() const;
 
 
+  bool IsMsBuildRestoreSupported() const;
+
 protected:
 protected:
   cmGlobalVisualStudio10Generator(cmake* cm, const std::string& name,
   cmGlobalVisualStudio10Generator(cmake* cm, const std::string& name,
                                   std::string const& platformInGeneratorName);
                                   std::string const& platformInGeneratorName);

+ 1 - 1
Source/cmGlobalVisualStudio7Generator.cxx

@@ -212,7 +212,7 @@ cmGlobalVisualStudio7Generator::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& projectName,
   const std::string& makeProgram, const std::string& projectName,
   const std::string& /*projectDir*/,
   const std::string& /*projectDir*/,
   std::vector<std::string> const& targetNames, const std::string& config,
   std::vector<std::string> const& targetNames, const std::string& config,
-  bool /*fast*/, int /*jobs*/, bool /*verbose*/,
+  int /*jobs*/, bool /*verbose*/, const cmBuildOptions& /*buildOptions*/,
   std::vector<std::string> const& makeOptions)
   std::vector<std::string> const& makeOptions)
 {
 {
   // Select the caller- or user-preferred make program, else devenv.
   // Select the caller- or user-preferred make program, else devenv.

+ 2 - 1
Source/cmGlobalVisualStudio7Generator.h

@@ -69,7 +69,8 @@ public:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
-    const std::string& config, bool fast, int jobs, bool verbose,
+    const std::string& config, int jobs, bool verbose,
+    const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
       std::vector<std::string>()) override;
 
 

+ 4 - 3
Source/cmGlobalWatcomWMakeGenerator.cxx

@@ -65,12 +65,13 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
 cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
 cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& projectName,
   const std::string& makeProgram, const std::string& projectName,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
-  const std::string& config, bool fast, int /*jobs*/, bool verbose,
+  const std::string& config, int /*jobs*/, bool verbose,
+  const cmBuildOptions& buildOptions,
   std::vector<std::string> const& makeOptions)
   std::vector<std::string> const& makeOptions)
 {
 {
   return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
   return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
-    makeProgram, projectName, projectDir, targetNames, config, fast,
-    cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
+    makeProgram, projectName, projectDir, targetNames, config,
+    cmake::NO_BUILD_PARALLEL_LEVEL, verbose, buildOptions, makeOptions);
 }
 }
 
 
 void cmGlobalWatcomWMakeGenerator::PrintBuildCommandAdvice(std::ostream& os,
 void cmGlobalWatcomWMakeGenerator::PrintBuildCommandAdvice(std::ostream& os,

+ 3 - 1
Source/cmGlobalWatcomWMakeGenerator.h

@@ -9,6 +9,7 @@
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
 
 
+#include "cmBuildOptions.h"
 #include "cmGlobalGeneratorFactory.h"
 #include "cmGlobalGeneratorFactory.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
 
 
@@ -57,7 +58,8 @@ protected:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
-    const std::string& config, bool fast, int jobs, bool verbose,
+    const std::string& config, int jobs, bool verbose,
+    const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
       std::vector<std::string>()) override;
 
 

+ 1 - 1
Source/cmGlobalXCodeGenerator.cxx

@@ -478,7 +478,7 @@ cmGlobalXCodeGenerator::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& projectName,
   const std::string& makeProgram, const std::string& projectName,
   const std::string& /*projectDir*/,
   const std::string& /*projectDir*/,
   std::vector<std::string> const& targetNames, const std::string& config,
   std::vector<std::string> const& targetNames, const std::string& config,
-  bool /*fast*/, int jobs, bool /*verbose*/,
+  int jobs, bool /*verbose*/, const cmBuildOptions& /*buildOptions*/,
   std::vector<std::string> const& makeOptions)
   std::vector<std::string> const& makeOptions)
 {
 {
   GeneratedMakeCommand makeCommand;
   GeneratedMakeCommand makeCommand;

+ 2 - 1
Source/cmGlobalXCodeGenerator.h

@@ -80,7 +80,8 @@ public:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
     const std::string& projectDir, std::vector<std::string> const& targetNames,
-    const std::string& config, bool fast, int jobs, bool verbose,
+    const std::string& config, int jobs, bool verbose,
+    const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
       std::vector<std::string>()) override;
 
 

+ 35 - 5
Source/cmVisualStudio10TargetGenerator.cxx

@@ -431,6 +431,9 @@ void cmVisualStudio10TargetGenerator::Generate()
 
 
   // The groups are stored in a separate file for VS 10
   // The groups are stored in a separate file for VS 10
   this->WriteGroups();
   this->WriteGroups();
+
+  // Update cache with project-specific entries.
+  this->UpdateCache();
 }
 }
 
 
 void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
 void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
@@ -1000,11 +1003,9 @@ bool cmVisualStudio10TargetGenerator::HasCustomCommands() const
 
 
 void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0)
 void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0)
 {
 {
-  std::vector<std::string> packageReferences;
-  if (cmValue vsPackageReferences =
-        this->GeneratorTarget->GetProperty("VS_PACKAGE_REFERENCES")) {
-    cmExpandList(*vsPackageReferences, packageReferences);
-  }
+  std::vector<std::string> packageReferences =
+    this->GeneratorTarget->GetPackageReferences();
+
   if (!packageReferences.empty()) {
   if (!packageReferences.empty()) {
     Elem e1(e0, "ItemGroup");
     Elem e1(e0, "ItemGroup");
     for (std::string const& ri : packageReferences) {
     for (std::string const& ri : packageReferences) {
@@ -5375,3 +5376,32 @@ void cmVisualStudio10TargetGenerator::WriteStdOutEncodingUtf8(Elem& e1)
     e1.Element("StdOutEncoding", "UTF-8");
     e1.Element("StdOutEncoding", "UTF-8");
   }
   }
 }
 }
+
+void cmVisualStudio10TargetGenerator::UpdateCache()
+{
+  std::vector<std::string> packageReferences;
+
+  if (this->GeneratorTarget->HasPackageReferences()) {
+    // Store a cache entry that later determines, if a package restore is
+    // required.
+    this->GeneratorTarget->Makefile->AddCacheDefinition(
+      this->GeneratorTarget->GetName() + "_REQUIRES_VS_PACKAGE_RESTORE", "ON",
+      "Value Computed by CMake", cmStateEnums::STATIC);
+  } else {
+    // If there are any dependencies that require package restore, inherit the
+    // cache variable.
+    cmGlobalGenerator::TargetDependSet const& unordered =
+      this->GlobalGenerator->GetTargetDirectDepends(this->GeneratorTarget);
+    using OrderedTargetDependSet =
+      cmGlobalVisualStudioGenerator::OrderedTargetDependSet;
+    OrderedTargetDependSet depends(unordered, CMAKE_CHECK_BUILD_SYSTEM_TARGET);
+
+    for (cmGeneratorTarget const* dt : depends) {
+      if (dt->HasPackageReferences()) {
+        this->GeneratorTarget->Makefile->AddCacheDefinition(
+          this->GeneratorTarget->GetName() + "_REQUIRES_VS_PACKAGE_RESTORE",
+          "ON", "Value Computed by CMake", cmStateEnums::STATIC);
+      }
+    }
+  }
+}

+ 1 - 0
Source/cmVisualStudio10TargetGenerator.h

@@ -198,6 +198,7 @@ private:
   std::string GetCSharpSourceLink(cmSourceFile const* source);
   std::string GetCSharpSourceLink(cmSourceFile const* source);
 
 
   void WriteStdOutEncodingUtf8(Elem& e1);
   void WriteStdOutEncodingUtf8(Elem& e1);
+  void UpdateCache();
 
 
 private:
 private:
   friend class cmVS10GeneratorOptions;
   friend class cmVS10GeneratorOptions;

+ 10 - 5
Source/cmake.cxx

@@ -28,6 +28,7 @@
 
 
 #include "cm_sys_stat.h"
 #include "cm_sys_stat.h"
 
 
+#include "cmBuildOptions.h"
 #include "cmCMakePath.h"
 #include "cmCMakePath.h"
 #include "cmCMakePresetsGraph.h"
 #include "cmCMakePresetsGraph.h"
 #include "cmCommandLineArgument.h"
 #include "cmCommandLineArgument.h"
@@ -3244,8 +3245,8 @@ std::vector<std::string> cmake::GetDebugConfigs()
 
 
 int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
 int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
                  std::string config, std::vector<std::string> nativeOptions,
                  std::string config, std::vector<std::string> nativeOptions,
-                 bool clean, bool verbose, const std::string& presetName,
-                 bool listPresets)
+                 cmBuildOptions& buildOptions, bool verbose,
+                 const std::string& presetName, bool listPresets)
 {
 {
   this->SetHomeDirectory("");
   this->SetHomeDirectory("");
   this->SetHomeOutputDirectory("");
   this->SetHomeOutputDirectory("");
@@ -3351,8 +3352,12 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
       config = expandedPreset->Configuration;
       config = expandedPreset->Configuration;
     }
     }
 
 
-    if (!clean && expandedPreset->CleanFirst) {
-      clean = *expandedPreset->CleanFirst;
+    if (!buildOptions.Clean && expandedPreset->CleanFirst) {
+      buildOptions.Clean = *expandedPreset->CleanFirst;
+    }
+
+    if (expandedPreset->ResolvePackageReferences) {
+      buildOptions.ResolveMode = *expandedPreset->ResolvePackageReferences;
     }
     }
 
 
     if (!verbose && expandedPreset->Verbose) {
     if (!verbose && expandedPreset->Verbose) {
@@ -3491,7 +3496,7 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
 
 
   this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, jobs);
   this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, jobs);
   return this->GlobalGenerator->Build(
   return this->GlobalGenerator->Build(
-    jobs, "", dir, projName, targets, output, "", config, clean, false,
+    jobs, "", dir, projName, targets, output, "", config, buildOptions,
     verbose, cmDuration::zero(), cmSystemTools::OUTPUT_PASSTHROUGH,
     verbose, cmDuration::zero(), cmSystemTools::OUTPUT_PASSTHROUGH,
     nativeOptions);
     nativeOptions);
 }
 }

+ 3 - 2
Source/cmake.h

@@ -45,6 +45,7 @@ class cmMakefileProfilingData;
 #endif
 #endif
 class cmMessenger;
 class cmMessenger;
 class cmVariableWatch;
 class cmVariableWatch;
+struct cmBuildOptions;
 struct cmDocumentationEntry;
 struct cmDocumentationEntry;
 
 
 /** \brief Represents a cmake invocation.
 /** \brief Represents a cmake invocation.
@@ -587,8 +588,8 @@ public:
   //! run the --build option
   //! run the --build option
   int Build(int jobs, std::string dir, std::vector<std::string> targets,
   int Build(int jobs, std::string dir, std::vector<std::string> targets,
             std::string config, std::vector<std::string> nativeOptions,
             std::string config, std::vector<std::string> nativeOptions,
-            bool clean, bool verbose, const std::string& presetName,
-            bool listPresets);
+            cmBuildOptions& buildOptions, bool verbose,
+            const std::string& presetName, bool listPresets);
 
 
   //! run the --open option
   //! run the --open option
   bool Open(const std::string& dir, bool dryRun);
   bool Open(const std::string& dir, bool dryRun);

+ 26 - 1
Source/cmakemain.cxx

@@ -5,6 +5,7 @@
 
 
 #include <algorithm>
 #include <algorithm>
 #include <cassert>
 #include <cassert>
+#include <cctype>
 #include <climits>
 #include <climits>
 #include <cstdio>
 #include <cstdio>
 #include <cstring>
 #include <cstring>
@@ -19,6 +20,7 @@
 
 
 #include <cm3p/uv.h>
 #include <cm3p/uv.h>
 
 
+#include "cmBuildOptions.h"
 #include "cmCommandLineArgument.h"
 #include "cmCommandLineArgument.h"
 #include "cmConsoleBuf.h"
 #include "cmConsoleBuf.h"
 #include "cmDocumentationEntry.h" // IWYU pragma: keep
 #include "cmDocumentationEntry.h" // IWYU pragma: keep
@@ -445,6 +447,7 @@ int do_build(int ac, char const* const* av)
   bool cleanFirst = false;
   bool cleanFirst = false;
   bool foundClean = false;
   bool foundClean = false;
   bool foundNonClean = false;
   bool foundNonClean = false;
+  PackageResolveMode resolveMode = PackageResolveMode::FromCacheVariable;
   bool verbose = cmSystemTools::HasEnv("VERBOSE");
   bool verbose = cmSystemTools::HasEnv("VERBOSE");
   std::string presetName;
   std::string presetName;
   bool listPresets = false;
   bool listPresets = false;
@@ -478,6 +481,22 @@ int do_build(int ac, char const* const* av)
     }
     }
     return false;
     return false;
   };
   };
+  auto resolvePackagesLambda = [&](std::string const& value) -> bool {
+    std::string v = value;
+    std::transform(v.begin(), v.end(), v.begin(), ::tolower);
+
+    if (v == "on") {
+      resolveMode = PackageResolveMode::Force;
+    } else if (v == "only") {
+      resolveMode = PackageResolveMode::OnlyResolve;
+    } else if (v == "off") {
+      resolveMode = PackageResolveMode::Disable;
+    } else {
+      return false;
+    }
+
+    return true;
+  };
   auto verboseLambda = [&](std::string const&) -> bool {
   auto verboseLambda = [&](std::string const&) -> bool {
     verbose = true;
     verbose = true;
     return true;
     return true;
@@ -514,6 +533,8 @@ int do_build(int ac, char const* const* av)
                        cleanFirst = true;
                        cleanFirst = true;
                        return true;
                        return true;
                      } },
                      } },
+    CommandArgument{ "--resolve-package-references",
+                     CommandArgument::Values::One, resolvePackagesLambda },
     CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda },
     CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda },
     CommandArgument{ "--verbose", CommandArgument::Values::Zero,
     CommandArgument{ "--verbose", CommandArgument::Values::Zero,
                      verboseLambda },
                      verboseLambda },
@@ -639,6 +660,8 @@ int do_build(int ac, char const* const* av)
       "  --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
       "  --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
       "  --clean-first  = Build target 'clean' first, then build.\n"
       "  --clean-first  = Build target 'clean' first, then build.\n"
       "                   (To clean only, use --target 'clean'.)\n"
       "                   (To clean only, use --target 'clean'.)\n"
+      "  --resolve-package-references={on|only|off}\n"
+      "                 = Restore/resolve package references during build.\n"
       "  --verbose, -v  = Enable verbose output - if supported - including\n"
       "  --verbose, -v  = Enable verbose output - if supported - including\n"
       "                   the build commands to be executed. \n"
       "                   the build commands to be executed. \n"
       "  --             = Pass remaining options to the native tool.\n"
       "  --             = Pass remaining options to the native tool.\n"
@@ -656,8 +679,10 @@ int do_build(int ac, char const* const* av)
     cmakemainProgressCallback(msg, prog, &cm);
     cmakemainProgressCallback(msg, prog, &cm);
   });
   });
 
 
+  cmBuildOptions buildOptions(cleanFirst, false, resolveMode);
+
   return cm.Build(jobs, std::move(dir), std::move(targets), std::move(config),
   return cm.Build(jobs, std::move(dir), std::move(targets), std::move(config),
-                  std::move(nativeOptions), cleanFirst, verbose, presetName,
+                  std::move(nativeOptions), buildOptions, verbose, presetName,
                   listPresets);
                   listPresets);
 #endif
 #endif
 }
 }

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -619,6 +619,7 @@ endif()
 
 
 if(CMAKE_GENERATOR MATCHES "^Visual Studio (1[6-9]|[2-9][0-9])")
 if(CMAKE_GENERATOR MATCHES "^Visual Studio (1[6-9]|[2-9][0-9])")
   add_RunCMake_test(VsDotnetSdk)
   add_RunCMake_test(VsDotnetSdk)
+  add_RunCMake_test(VsNugetPackageRestore)
 endif()
 endif()
 
 
 if(XCODE_VERSION)
 if(XCODE_VERSION)

+ 7 - 1
Tests/RunCMake/CMakePresetsBuild/Good.json.in

@@ -1,5 +1,5 @@
 {
 {
-    "version": 2,
+    "version": 4,
     "configurePresets": [
     "configurePresets": [
         {
         {
             "name": "default",
             "name": "default",
@@ -78,6 +78,12 @@
             "name": "singleTarget",
             "name": "singleTarget",
             "inherits": "build-default",
             "inherits": "build-default",
             "targets": "good"
             "targets": "good"
+        },
+        {
+            "name": "initResolve",
+            "inherits": "build-default",
+            "targets": "good",
+            "resolvePackageReferences": "off"
         }
         }
     ]
     ]
 }
 }

+ 1 - 1
Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake

@@ -70,7 +70,7 @@ else()
   set(Good_json_jobs [["jobs": 0,]])
   set(Good_json_jobs [["jobs": 0,]])
 endif()
 endif()
 
 
-run_cmake_build_presets(Good "default;other" "build-other;withEnvironment;noEnvironment;macros;vendorObject;singleTarget")
+run_cmake_build_presets(Good "default;other" "build-other;withEnvironment;noEnvironment;macros;vendorObject;singleTarget;initResolve")
 run_cmake_build_presets(InvalidConfigurePreset "default" "badConfigurePreset")
 run_cmake_build_presets(InvalidConfigurePreset "default" "badConfigurePreset")
 run_cmake_build_presets(Condition "default" "enabled;disabled")
 run_cmake_build_presets(Condition "default" "enabled;disabled")
 
 

+ 1 - 0
Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-result.txt

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

+ 1 - 0
Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-stderr.txt

@@ -0,0 +1 @@
+^Usage: cmake --build <dir> +\[options\] \[-- \[native-options\]\]

+ 3 - 0
Tests/RunCMake/VsNugetPackageRestore/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.22)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 17 - 0
Tests/RunCMake/VsNugetPackageRestore/Package/CMakeLists.txt

@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.12)
+
+project(NuGetTestProject VERSION 1.0.0 LANGUAGES CSharp)
+
+add_library(NuGetPackage SHARED "Library.cs")
+set_target_properties(NuGetPackage PROPERTIES
+  VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.7.2"
+  VS_DOTNET_REFERENCES "System")
+install(TARGETS NuGetPackage)
+
+set(CPACK_GENERATOR "NuGet")
+set(CPACK_PACKAGE_NAME "NuGetTestProject")
+set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
+set(CPACK_PACKAGE_DESCRIPTION "Package to test automatic NuGet package restore.")
+set(CPACK_PACKAGE_VENDOR "CMake.org")
+
+include(CPack)

+ 9 - 0
Tests/RunCMake/VsNugetPackageRestore/Package/Library.cs

@@ -0,0 +1,9 @@
+using System;
+
+namespace CMake
+{
+    public class NuGetTest
+    {
+        public static int GetNumber() => 42;
+    }
+}

+ 14 - 0
Tests/RunCMake/VsNugetPackageRestore/Program.cs

@@ -0,0 +1,14 @@
+using System;
+using CMake;
+
+namespace Test
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            Console.WriteLine(NuGetTest.GetNumber());
+            Console.ReadKey();
+        }
+    }
+}

+ 5 - 0
Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/.nupkg.metadata

@@ -0,0 +1,5 @@
+{
+  "version": 2,
+  "contentHash": "2sG1Ws4da8r6qj7rUAZ1GaOjkELonH0X+vR9yfDwgg+QxG0cpRIfGqEXKAkGT+UCwU24ogJcm8IA9dXv5zmLXg==",
+  "source": null
+}

BIN
Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg


+ 1 - 0
Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg.sha512

@@ -0,0 +1 @@
+2sG1Ws4da8r6qj7rUAZ1GaOjkELonH0X+vR9yfDwgg+QxG0cpRIfGqEXKAkGT+UCwU24ogJcm8IA9dXv5zmLXg==

+ 11 - 0
Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.nuspec

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
+  <metadata>
+    <id>NuGetTestProject</id>
+    <version>1.0.0</version>
+    <authors>CMake.org</authors>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <description>Package to test automatic NuGet package restore.</description>
+    <summary>NuGetTestProject built using CMake</summary>
+  </metadata>
+</package>

+ 12 - 0
Tests/RunCMake/VsNugetPackageRestore/RunCMakeTest.cmake

@@ -0,0 +1,12 @@
+cmake_policy(SET CMP0053 NEW)
+include(RunCMake)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VsNugetPackageRestore)
+run_cmake(VsNugetPackageRestore)
+
+set(RunCMake_TEST_NO_CLEAN 1)
+run_cmake_command(vs-nuget-package-restore-off ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR} --resolve-package-references=off)
+run_cmake_command(vs-nuget-package-restore-only ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR} --resolve-package-references=only)
+run_cmake_command(vs-nuget-package-restore-on ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR} --resolve-package-references=on)
+run_cmake_command(vs-nuget-package-restore-wrong ${CMAKE_COMMAND} --build ${RunCMake_TEST_BINARY_DIR} --resolve-package-references=wrong)
+set(RunCMake_TEST_NO_CLEAN 0)

+ 9 - 0
Tests/RunCMake/VsNugetPackageRestore/VsNugetPackageRestore.cmake

@@ -0,0 +1,9 @@
+enable_language(CSharp)
+
+add_executable(TestProgram "Program.cs")
+configure_file("nuget.config.in" "nuget.config")
+set_target_properties(TestProgram PROPERTIES
+  VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.7.2"
+  VS_DOTNET_REFERENCES "System"
+  VS_PACKAGE_REFERENCES "NuGetTestProject_1.0.0"
+)

+ 7 - 0
Tests/RunCMake/VsNugetPackageRestore/nuget.config.in

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <packageSources>
+    <clear />
+    <add key="local" value="@CMAKE_CURRENT_SOURCE_DIR@/Repository/" />
+  </packageSources>
+</configuration>

+ 1 - 0
Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-result.txt

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

+ 1 - 0
Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-stderr.txt

@@ -0,0 +1 @@
+^$

+ 1 - 0
Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-result.txt

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

+ 1 - 0
Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-stderr.txt

@@ -0,0 +1 @@
+^Usage: cmake --build <dir> +\[options\] \[-- \[native-options\]\]