summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2022-01-24 16:46:15 (GMT)
committerKitware Robot <kwrobot@kitware.com>2022-01-24 16:46:29 (GMT)
commit63154cbf4501e11cae281eccbbdf9eceb453dae1 (patch)
treebe8490cf000e62f532a40fb37f652f9f4e7e477e
parent25441f26171531ff114f3b9a6fad6ee2edc7ef29 (diff)
parent9aa7831f05e924830848822aecdb43aa7261bc11 (diff)
downloadCMake-63154cbf4501e11cae281eccbbdf9eceb453dae1.zip
CMake-63154cbf4501e11cae281eccbbdf9eceb453dae1.tar.gz
CMake-63154cbf4501e11cae281eccbbdf9eceb453dae1.tar.bz2
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 <kwrobot@kitware.com> Merge-request: !6761
-rw-r--r--Help/manual/cmake-presets.7.rst36
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/manual/cmake.1.rst24
-rw-r--r--Help/manual/presets/schema.json61
-rw-r--r--Help/release/dev/vs-package-restore.rst13
-rw-r--r--Help/variable/CMAKE_VS_NUGET_PACKAGE_RESTORE.rst22
-rw-r--r--Source/CMakeLists.txt1
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx6
-rw-r--r--Source/cmBuildOptions.h44
-rw-r--r--Source/cmCMakePresetsGraph.cxx3
-rw-r--r--Source/cmCMakePresetsGraph.h3
-rw-r--r--Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx35
-rw-r--r--Source/cmGeneratorTarget.cxx20
-rw-r--r--Source/cmGeneratorTarget.h3
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.cxx7
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.h3
-rw-r--r--Source/cmGlobalGenerator.cxx22
-rw-r--r--Source/cmGlobalGenerator.h8
-rw-r--r--Source/cmGlobalGhsMultiGenerator.cxx3
-rw-r--r--Source/cmGlobalGhsMultiGenerator.h4
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.cxx7
-rw-r--r--Source/cmGlobalJOMMakefileGenerator.h3
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.cxx7
-rw-r--r--Source/cmGlobalNMakeMakefileGenerator.h3
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx2
-rw-r--r--Source/cmGlobalNinjaGenerator.h4
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.cxx4
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h4
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx83
-rw-r--r--Source/cmGlobalVisualStudio10Generator.h5
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx2
-rw-r--r--Source/cmGlobalVisualStudio7Generator.h3
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.cxx7
-rw-r--r--Source/cmGlobalWatcomWMakeGenerator.h4
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx2
-rw-r--r--Source/cmGlobalXCodeGenerator.h3
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx40
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h1
-rw-r--r--Source/cmake.cxx15
-rw-r--r--Source/cmake.h5
-rw-r--r--Source/cmakemain.cxx27
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/Good.json.in8
-rw-r--r--Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-stderr.txt1
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/Package/CMakeLists.txt17
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/Package/Library.cs9
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/Program.cs14
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/.nupkg.metadata5
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkgbin0 -> 5664 bytes
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg.sha5121
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.nuspec11
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/RunCMakeTest.cmake12
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/VsNugetPackageRestore.cmake9
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/nuget.config.in7
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-result.txt1
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-stderr.txt1
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-result.txt1
-rw-r--r--Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-stderr.txt1
61 files changed, 589 insertions, 66 deletions
diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst
index e702d97..31bd9c0 100644
--- a/Help/manual/cmake-presets.7.rst
+++ b/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
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``
An optional bool. If true, equivalent to passing ``--verbose`` on the
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 920bfe0..04c5a53 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -119,6 +119,7 @@ Variables that Provide Information
/variable/CMAKE_VS_DEVENV_COMMAND
/variable/CMAKE_VS_MSBUILD_COMMAND
/variable/CMAKE_VS_NsightTegra_VERSION
+ /variable/CMAKE_VS_NUGET_PACKAGE_RESTORE
/variable/CMAKE_VS_PLATFORM_NAME
/variable/CMAKE_VS_PLATFORM_NAME_DEFAULT
/variable/CMAKE_VS_PLATFORM_TOOLSET
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 04e2eda..1463f0a 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -463,6 +463,30 @@ following options:
Build target ``clean`` first, then build.
(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``
Ignored. Behavior is default in CMake >= 3.0.
diff --git a/Help/manual/presets/schema.json b/Help/manual/presets/schema.json
index 327291d..12f8b5e 100644
--- a/Help/manual/presets/schema.json
+++ b/Help/manual/presets/schema.json
@@ -52,7 +52,7 @@
"cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
"vendor": { "$ref": "#/definitions/vendor" },
"configurePresets": { "$ref": "#/definitions/configurePresetsV3"},
- "buildPresets": { "$ref": "#/definitions/buildPresetsV3"},
+ "buildPresets": { "$ref": "#/definitions/buildPresetsV4"},
"testPresets": { "$ref": "#/definitions/testPresetsV3"},
"include": { "$ref": "#/definitions/include"}
},
@@ -427,9 +427,25 @@
"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": {
"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": {
"type": "object",
"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": {
"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": [
{ "$ref": "#/definitions/buildPresetsItemsV3" },
{ "$ref": "#/definitions/buildPresetsItemsV2" }
@@ -624,7 +675,7 @@
},
"testPresetsItemsV3": {
"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": {
"type": "object",
"properties": {
@@ -949,7 +1000,7 @@
},
"testPresetsV3": {
"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": [
{ "$ref": "#/definitions/testPresetsItemsV2" },
{ "$ref": "#/definitions/testPresetsItemsV3" }
diff --git a/Help/release/dev/vs-package-restore.rst b/Help/release/dev/vs-package-restore.rst
new file mode 100644
index 0000000..e8b5f0c
--- /dev/null
+++ b/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.
diff --git a/Help/variable/CMAKE_VS_NUGET_PACKAGE_RESTORE.rst b/Help/variable/CMAKE_VS_NUGET_PACKAGE_RESTORE.rst
new file mode 100644
index 0000000..7160726
--- /dev/null
+++ b/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.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index b31b8dc..ddcdd7e 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -155,6 +155,7 @@ set(SRCS
cmBinUtilsWindowsPELinker.h
cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
+ cmBuildOptions.h
cmCacheManager.cxx
cmCacheManager.h
cmCLocaleEnvironmentScope.h
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index adfc8ef..e09b4dd 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -9,6 +9,7 @@
#include "cmsys/Process.h"
+#include "cmBuildOptions.h"
#include "cmCTest.h"
#include "cmCTestTestHandler.h"
#include "cmGlobalGenerator.h"
@@ -263,10 +264,13 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
if (!config) {
config = "Debug";
}
+
+ cmBuildOptions buildOptions(!this->BuildNoClean, false,
+ PackageResolveMode::Disable);
int retVal = cm.GetGlobalGenerator()->Build(
cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir,
this->BuildProject, { tar }, output, this->BuildMakeProgram, config,
- !this->BuildNoClean, false, false, remainingTime);
+ buildOptions, false, remainingTime);
out << output;
// if the build failed then return
if (retVal) {
diff --git a/Source/cmBuildOptions.h b/Source/cmBuildOptions.h
new file mode 100644
index 0000000..58baeef
--- /dev/null
+++ b/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;
+};
diff --git a/Source/cmCMakePresetsGraph.cxx b/Source/cmCMakePresetsGraph.cxx
index 238aa68..79e8191 100644
--- a/Source/cmCMakePresetsGraph.cxx
+++ b/Source/cmCMakePresetsGraph.cxx
@@ -724,6 +724,9 @@ cmCMakePresetsGraph::BuildPreset::VisitPresetInherit(
InheritOptionalValue(preset.CleanFirst, parent.CleanFirst);
InheritOptionalValue(preset.Verbose, parent.Verbose);
InheritVector(preset.NativeToolOptions, parent.NativeToolOptions);
+ if (!preset.ResolvePackageReferences) {
+ preset.ResolvePackageReferences = parent.ResolvePackageReferences;
+ }
return ReadFileResult::READ_OK;
}
diff --git a/Source/cmCMakePresetsGraph.h b/Source/cmCMakePresetsGraph.h
index 8581809..d3a5cfc 100644
--- a/Source/cmCMakePresetsGraph.h
+++ b/Source/cmCMakePresetsGraph.h
@@ -14,6 +14,8 @@
#include <cm/optional>
+enum class PackageResolveMode;
+
class cmCMakePresetsGraph
{
public:
@@ -181,6 +183,7 @@ public:
cm::optional<bool> CleanFirst;
cm::optional<bool> Verbose;
std::vector<std::string> NativeToolOptions;
+ cm::optional<PackageResolveMode> ResolvePackageReferences;
ReadFileResult VisitPresetInherit(const Preset& parent) override;
ReadFileResult VisitPresetAfterInherit(int /* version */) override;
diff --git a/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx b/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx
index ef605d1..eefe2fe 100644
--- a/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx
+++ b/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx
@@ -12,6 +12,7 @@
#include <cm3p/json/value.h>
+#include "cmBuildOptions.h"
#include "cmCMakePresetsGraph.h"
#include "cmCMakePresetsGraphInternal.h"
#include "cmJSONHelpers.h"
@@ -20,6 +21,37 @@ namespace {
using ReadFileResult = cmCMakePresetsGraph::ReadFileResult;
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 =
cmJSONObjectHelper<BuildPreset, ReadFileResult>(
ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
@@ -59,7 +91,8 @@ auto const BuildPresetHelper =
.Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
cmCMakePresetsGraphInternal::PresetVectorStringHelper, false)
.Bind("condition"_s, &BuildPreset::ConditionEvaluator,
- cmCMakePresetsGraphInternal::PresetConditionHelper, false);
+ cmCMakePresetsGraphInternal::PresetConditionHelper, false)
+ .Bind("resolvePackageReferences"_s, ResolvePackageReferencesHelper, false);
}
namespace cmCMakePresetsGraphInternal {
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 421e136..45e3b64 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -8102,6 +8102,26 @@ cmLinkItem cmGeneratorTarget::ResolveLinkItem(BT<std::string> const& name,
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
{
if (OutputInfo const* info = this->GetOutputInfo(config)) {
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 71212c4..a58dc93 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -424,6 +424,9 @@ public:
cmLinkItem ResolveLinkItem(BT<std::string> const& name,
cmLocalGenerator const* lg) const;
+ bool HasPackageReferences() const;
+ std::vector<std::string> GetPackageReferences() const;
+
// Compute the set of languages compiled by the target. This is
// computed every time it is called because the languages can change
// when source file properties are changed and we do not have enough
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
index 5503619..776ee40 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.cxx
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -71,12 +71,13 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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)
{
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(
diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h
index 646dfff..a280b81 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.h
+++ b/Source/cmGlobalBorlandMakefileGenerator.h
@@ -59,7 +59,8 @@ protected:
std::vector<GeneratedMakeCommand> GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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>()) override;
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 6433681..156ecce 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -1994,16 +1994,19 @@ int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
}
std::string config =
mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
+ cmBuildOptions defaultBuildOptions(false, fast, PackageResolveMode::Disable);
+
return this->Build(jobs, srcdir, bindir, projectName, newTarget, output, "",
- config, false, fast, false, this->TryCompileTimeout);
+ config, defaultBuildOptions, false,
+ this->TryCompileTimeout);
}
std::vector<cmGlobalGenerator::GeneratedMakeCommand>
cmGlobalGenerator::GenerateBuildCommand(
const std::string& /*unused*/, const std::string& /*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;
makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
@@ -2021,7 +2024,7 @@ int cmGlobalGenerator::Build(
int jobs, const std::string& /*unused*/, const std::string& bindir,
const std::string& projectName, const std::vector<std::string>& targets,
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,
std::vector<std::string> const& nativeOptions)
{
@@ -2053,9 +2056,9 @@ int cmGlobalGenerator::Build(
std::string 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.
if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
@@ -2064,10 +2067,11 @@ int cmGlobalGenerator::Build(
}
// should we do a clean first?
- if (clean) {
+ if (buildOptions.Clean) {
std::vector<GeneratedMakeCommand> cleanCommand =
this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir,
- { "clean" }, realConfig, fast, jobs, verbose);
+ { "clean" }, realConfig, jobs, verbose,
+ buildOptions);
output += "\nRun Clean Command:";
output += cleanCommand.front().Printable();
output += "\n";
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 2406798..a43d4a6 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -20,6 +20,7 @@
#include "cm_codecvt.hxx"
+#include "cmBuildOptions.h"
#include "cmCustomCommandLines.h"
#include "cmDuration.h"
#include "cmExportSet.h"
@@ -229,8 +230,8 @@ public:
int jobs, const std::string& srcdir, const std::string& bindir,
const std::string& projectName,
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,
std::vector<std::string> const& nativeOptions =
std::vector<std::string>());
@@ -248,7 +249,8 @@ public:
virtual std::vector<GeneratedMakeCommand> GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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>());
virtual void PrintBuildCommandAdvice(std::ostream& os, int jobs) const;
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index bf537b7..5e51dd2 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -510,7 +510,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
cmGlobalGhsMultiGenerator::GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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)
{
GeneratedMakeCommand makeCommand = {};
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
index 9076e0e..26ea3c7 100644
--- a/Source/cmGlobalGhsMultiGenerator.h
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -9,6 +9,7 @@
#include <utility>
#include <vector>
+#include "cmBuildOptions.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
#include "cmTargetDepend.h"
@@ -87,7 +88,8 @@ protected:
std::vector<GeneratedMakeCommand> GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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>()) override;
diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx
index 1b406a6..1a625cc 100644
--- a/Source/cmGlobalJOMMakefileGenerator.cxx
+++ b/Source/cmGlobalJOMMakefileGenerator.cxx
@@ -63,7 +63,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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> jomMakeOptions;
@@ -81,6 +82,6 @@ cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
}
return cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
- makeProgram, projectName, projectDir, targetNames, config, fast, jobs,
- verbose, jomMakeOptions);
+ makeProgram, projectName, projectDir, targetNames, config, jobs, verbose,
+ buildOptions, jomMakeOptions);
}
diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h
index 8229745..332d1cf 100644
--- a/Source/cmGlobalJOMMakefileGenerator.h
+++ b/Source/cmGlobalJOMMakefileGenerator.h
@@ -52,7 +52,8 @@ protected:
std::vector<GeneratedMakeCommand> GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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>()) override;
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
index 9f3d30e..55748cf 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.cxx
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -106,7 +106,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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> nmakeMakeOptions;
@@ -117,8 +118,8 @@ cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
cm::append(nmakeMakeOptions, makeOptions);
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,
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
index ca5b8d6..b3574eb 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.h
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -58,7 +58,8 @@ protected:
std::vector<GeneratedMakeCommand> GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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>()) override;
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 19c4ee3..5b85179 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -955,7 +955,7 @@ cmGlobalNinjaGenerator::GenerateBuildCommand(
const std::string& makeProgram, const std::string& /*projectName*/,
const std::string& /*projectDir*/,
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)
{
GeneratedMakeCommand makeCommand;
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 84fc06c..c619b2e 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -18,6 +18,7 @@
#include "cm_codecvt.hxx"
+#include "cmBuildOptions.h"
#include "cmGeneratedFileStream.h"
#include "cmGlobalCommonGenerator.h"
#include "cmGlobalGeneratorFactory.h"
@@ -199,7 +200,8 @@ public:
std::vector<GeneratedMakeCommand> GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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>()) override;
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 0556540..ab9ca50 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -518,7 +518,7 @@ cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
const std::string& makeProgram, const std::string& /*projectName*/,
const std::string& /*projectDir*/,
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)
{
GeneratedMakeCommand makeCommand;
@@ -548,7 +548,7 @@ cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
makeCommand.Add(makeOptions.begin(), makeOptions.end());
for (auto tname : targetNames) {
if (!tname.empty()) {
- if (fast) {
+ if (buildOptions.Fast) {
tname += "/fast";
}
cmSystemTools::ConvertToOutputSlashes(tname);
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 94ee476..5157826 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -12,6 +12,7 @@
#include <string>
#include <vector>
+#include "cmBuildOptions.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalCommonGenerator.h"
#include "cmGlobalGeneratorFactory.h"
@@ -163,7 +164,8 @@ public:
std::vector<GeneratedMakeCommand> GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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>()) override;
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index d7bc05d..e9824fb 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -724,6 +724,10 @@ void cmGlobalVisualStudio10Generator::Generate()
/* clang-format on */
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(
@@ -1099,7 +1103,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
cmGlobalVisualStudio10Generator::GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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<GeneratedMakeCommand> makeCommands;
@@ -1145,8 +1150,8 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand(
if (useDevEnv) {
// Use devenv to build solutions containing Intel Fortran projects.
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;
@@ -1178,8 +1183,66 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand(
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=";
if (!config.empty()) {
configArg += config;
@@ -1559,6 +1622,18 @@ cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetNasmFlagTable() const
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 const& toolset = this->GetPlatformToolsetString();
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index c8fd149..4977a84 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -43,7 +43,8 @@ public:
std::vector<GeneratedMakeCommand> GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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>()) override;
@@ -172,6 +173,8 @@ public:
cmIDEFlagTable const* GetMasmFlagTable() const;
cmIDEFlagTable const* GetNasmFlagTable() const;
+ bool IsMsBuildRestoreSupported() const;
+
protected:
cmGlobalVisualStudio10Generator(cmake* cm, const std::string& name,
std::string const& platformInGeneratorName);
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index c72b109..91012dd 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -212,7 +212,7 @@ cmGlobalVisualStudio7Generator::GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
const std::string& /*projectDir*/,
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)
{
// Select the caller- or user-preferred make program, else devenv.
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index d1fb804..33f1063 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -69,7 +69,8 @@ public:
std::vector<GeneratedMakeCommand> GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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>()) override;
diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx
index 3e2d92d..fb2a8b6 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.cxx
+++ b/Source/cmGlobalWatcomWMakeGenerator.cxx
@@ -65,12 +65,13 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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)
{
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,
diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h
index da39d3f..eb93934 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.h
+++ b/Source/cmGlobalWatcomWMakeGenerator.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "cmBuildOptions.h"
#include "cmGlobalGeneratorFactory.h"
#include "cmGlobalUnixMakefileGenerator3.h"
@@ -57,7 +58,8 @@ protected:
std::vector<GeneratedMakeCommand> GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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>()) override;
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index bc2a6f7..203addd 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -478,7 +478,7 @@ cmGlobalXCodeGenerator::GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
const std::string& /*projectDir*/,
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)
{
GeneratedMakeCommand makeCommand;
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 5917db3..ff6ffe8 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -80,7 +80,8 @@ public:
std::vector<GeneratedMakeCommand> GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
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>()) override;
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 96dcf0b..89011a2 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -431,6 +431,9 @@ void cmVisualStudio10TargetGenerator::Generate()
// The groups are stored in a separate file for VS 10
this->WriteGroups();
+
+ // Update cache with project-specific entries.
+ this->UpdateCache();
}
void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile(
@@ -1000,11 +1003,9 @@ bool cmVisualStudio10TargetGenerator::HasCustomCommands() const
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()) {
Elem e1(e0, "ItemGroup");
for (std::string const& ri : packageReferences) {
@@ -5375,3 +5376,32 @@ void cmVisualStudio10TargetGenerator::WriteStdOutEncodingUtf8(Elem& e1)
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);
+ }
+ }
+ }
+}
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 79aa5e8..8d777a3 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -198,6 +198,7 @@ private:
std::string GetCSharpSourceLink(cmSourceFile const* source);
void WriteStdOutEncodingUtf8(Elem& e1);
+ void UpdateCache();
private:
friend class cmVS10GeneratorOptions;
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 72b26e1..ef4e37b 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -28,6 +28,7 @@
#include "cm_sys_stat.h"
+#include "cmBuildOptions.h"
#include "cmCMakePath.h"
#include "cmCMakePresetsGraph.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,
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->SetHomeOutputDirectory("");
@@ -3351,8 +3352,12 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
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) {
@@ -3491,7 +3496,7 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, jobs);
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,
nativeOptions);
}
diff --git a/Source/cmake.h b/Source/cmake.h
index aee9c04..1187be5 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -45,6 +45,7 @@ class cmMakefileProfilingData;
#endif
class cmMessenger;
class cmVariableWatch;
+struct cmBuildOptions;
struct cmDocumentationEntry;
/** \brief Represents a cmake invocation.
@@ -587,8 +588,8 @@ public:
//! run the --build option
int Build(int jobs, std::string dir, std::vector<std::string> targets,
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
bool Open(const std::string& dir, bool dryRun);
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 00aafdc..22fdcf8 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -5,6 +5,7 @@
#include <algorithm>
#include <cassert>
+#include <cctype>
#include <climits>
#include <cstdio>
#include <cstring>
@@ -19,6 +20,7 @@
#include <cm3p/uv.h>
+#include "cmBuildOptions.h"
#include "cmCommandLineArgument.h"
#include "cmConsoleBuf.h"
#include "cmDocumentationEntry.h" // IWYU pragma: keep
@@ -445,6 +447,7 @@ int do_build(int ac, char const* const* av)
bool cleanFirst = false;
bool foundClean = false;
bool foundNonClean = false;
+ PackageResolveMode resolveMode = PackageResolveMode::FromCacheVariable;
bool verbose = cmSystemTools::HasEnv("VERBOSE");
std::string presetName;
bool listPresets = false;
@@ -478,6 +481,22 @@ int do_build(int ac, char const* const* av)
}
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 {
verbose = true;
return true;
@@ -514,6 +533,8 @@ int do_build(int ac, char const* const* av)
cleanFirst = true;
return true;
} },
+ CommandArgument{ "--resolve-package-references",
+ CommandArgument::Values::One, resolvePackagesLambda },
CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda },
CommandArgument{ "--verbose", CommandArgument::Values::Zero,
verboseLambda },
@@ -639,6 +660,8 @@ int do_build(int ac, char const* const* av)
" --config <cfg> = For multi-configuration tools, choose <cfg>.\n"
" --clean-first = Build target 'clean' first, then build.\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"
" the build commands to be executed. \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);
});
+ cmBuildOptions buildOptions(cleanFirst, false, resolveMode);
+
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);
#endif
}
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index dd786b8..6bea788 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -619,6 +619,7 @@ endif()
if(CMAKE_GENERATOR MATCHES "^Visual Studio (1[6-9]|[2-9][0-9])")
add_RunCMake_test(VsDotnetSdk)
+ add_RunCMake_test(VsNugetPackageRestore)
endif()
if(XCODE_VERSION)
diff --git a/Tests/RunCMake/CMakePresetsBuild/Good.json.in b/Tests/RunCMake/CMakePresetsBuild/Good.json.in
index c7f318c..568907c 100644
--- a/Tests/RunCMake/CMakePresetsBuild/Good.json.in
+++ b/Tests/RunCMake/CMakePresetsBuild/Good.json.in
@@ -1,5 +1,5 @@
{
- "version": 2,
+ "version": 4,
"configurePresets": [
{
"name": "default",
@@ -78,6 +78,12 @@
"name": "singleTarget",
"inherits": "build-default",
"targets": "good"
+ },
+ {
+ "name": "initResolve",
+ "inherits": "build-default",
+ "targets": "good",
+ "resolvePackageReferences": "off"
}
]
}
diff --git a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
index b37c770..2fe0407 100644
--- a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
@@ -70,7 +70,7 @@ else()
set(Good_json_jobs [["jobs": 0,]])
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(Condition "default" "enabled;disabled")
diff --git a/Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-result.txt b/Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-stderr.txt b/Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-stderr.txt
new file mode 100644
index 0000000..4811bea
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-stderr.txt
@@ -0,0 +1 @@
+^Usage: cmake --build <dir> +\[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/VsNugetPackageRestore/CMakeLists.txt b/Tests/RunCMake/VsNugetPackageRestore/CMakeLists.txt
new file mode 100644
index 0000000..d8200fc
--- /dev/null
+++ b/Tests/RunCMake/VsNugetPackageRestore/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.22)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/VsNugetPackageRestore/Package/CMakeLists.txt b/Tests/RunCMake/VsNugetPackageRestore/Package/CMakeLists.txt
new file mode 100644
index 0000000..56920d9
--- /dev/null
+++ b/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)
diff --git a/Tests/RunCMake/VsNugetPackageRestore/Package/Library.cs b/Tests/RunCMake/VsNugetPackageRestore/Package/Library.cs
new file mode 100644
index 0000000..d9ae85a
--- /dev/null
+++ b/Tests/RunCMake/VsNugetPackageRestore/Package/Library.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace CMake
+{
+ public class NuGetTest
+ {
+ public static int GetNumber() => 42;
+ }
+}
diff --git a/Tests/RunCMake/VsNugetPackageRestore/Program.cs b/Tests/RunCMake/VsNugetPackageRestore/Program.cs
new file mode 100644
index 0000000..681461f
--- /dev/null
+++ b/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();
+ }
+ }
+}
diff --git a/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/.nupkg.metadata b/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/.nupkg.metadata
new file mode 100644
index 0000000..6a87d0a
--- /dev/null
+++ b/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/.nupkg.metadata
@@ -0,0 +1,5 @@
+{
+ "version": 2,
+ "contentHash": "2sG1Ws4da8r6qj7rUAZ1GaOjkELonH0X+vR9yfDwgg+QxG0cpRIfGqEXKAkGT+UCwU24ogJcm8IA9dXv5zmLXg==",
+ "source": null
+}
diff --git a/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg b/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg
new file mode 100644
index 0000000..5569a29
--- /dev/null
+++ b/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg
Binary files differ
diff --git a/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg.sha512 b/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg.sha512
new file mode 100644
index 0000000..5526b76
--- /dev/null
+++ b/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg.sha512
@@ -0,0 +1 @@
+2sG1Ws4da8r6qj7rUAZ1GaOjkELonH0X+vR9yfDwgg+QxG0cpRIfGqEXKAkGT+UCwU24ogJcm8IA9dXv5zmLXg==
diff --git a/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.nuspec b/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.nuspec
new file mode 100644
index 0000000..9a943a8
--- /dev/null
+++ b/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>
diff --git a/Tests/RunCMake/VsNugetPackageRestore/RunCMakeTest.cmake b/Tests/RunCMake/VsNugetPackageRestore/RunCMakeTest.cmake
new file mode 100644
index 0000000..625167c
--- /dev/null
+++ b/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)
diff --git a/Tests/RunCMake/VsNugetPackageRestore/VsNugetPackageRestore.cmake b/Tests/RunCMake/VsNugetPackageRestore/VsNugetPackageRestore.cmake
new file mode 100644
index 0000000..a0227df
--- /dev/null
+++ b/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"
+)
diff --git a/Tests/RunCMake/VsNugetPackageRestore/nuget.config.in b/Tests/RunCMake/VsNugetPackageRestore/nuget.config.in
new file mode 100644
index 0000000..2e54c8f
--- /dev/null
+++ b/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>
diff --git a/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-result.txt b/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-stderr.txt b/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-stderr.txt
new file mode 100644
index 0000000..10f3293
--- /dev/null
+++ b/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-off-stderr.txt
@@ -0,0 +1 @@
+^$
diff --git a/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-result.txt b/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-stderr.txt b/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-stderr.txt
new file mode 100644
index 0000000..4811bea
--- /dev/null
+++ b/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-stderr.txt
@@ -0,0 +1 @@
+^Usage: cmake --build <dir> +\[options\] \[-- \[native-options\]\]