diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst index e702d970da..31bd9c0fde 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 920bfe0cdd..04c5a533c3 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 04e2eda447..1463f0a23f 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=`` + .. 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 327291d0bc..12f8b5ec17 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 0000000000..e8b5f0c653 --- /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=`` + 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 0000000000..716072630a --- /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 b31b8dcaa6..ddcdd7e90e 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 adfc8ef774..e09b4dd40a 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 0000000000..58baeef759 --- /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 238aa68cdb..79e8191b55 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 8581809f4d..d3a5cfc0ea 100644 --- a/Source/cmCMakePresetsGraph.h +++ b/Source/cmCMakePresetsGraph.h @@ -14,6 +14,8 @@ #include +enum class PackageResolveMode; + class cmCMakePresetsGraph { public: @@ -181,6 +183,7 @@ public: cm::optional CleanFirst; cm::optional Verbose; std::vector NativeToolOptions; + cm::optional ResolvePackageReferences; ReadFileResult VisitPresetInherit(const Preset& parent) override; ReadFileResult VisitPresetAfterInherit(int /* version */) override; diff --git a/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx b/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx index ef605d15fe..eefe2fe28a 100644 --- a/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx +++ b/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx @@ -12,6 +12,7 @@ #include +#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& 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 const + ResolvePackageReferencesHelper = + [](BuildPreset& out, const Json::Value* value) -> ReadFileResult { + return PackageResolveModeHelper(out.ResolvePackageReferences, value); +}; + auto const BuildPresetHelper = cmJSONObjectHelper( 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 421e13671a..45e3b64d1b 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -8102,6 +8102,26 @@ cmLinkItem cmGeneratorTarget::ResolveLinkItem(BT const& name, return cmLinkItem(resolved.Target, false, bt); } +bool cmGeneratorTarget::HasPackageReferences() const +{ + return this->IsInBuildSystem() && + !this->GetProperty("VS_PACKAGE_REFERENCES")->empty(); +} + +std::vector cmGeneratorTarget::GetPackageReferences() const +{ + std::vector 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 71212c4faf..a58dc93712 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -424,6 +424,9 @@ public: cmLinkItem ResolveLinkItem(BT const& name, cmLocalGenerator const* lg) const; + bool HasPackageReferences() const; + std::vector 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 5503619144..776ee406c5 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.cxx +++ b/Source/cmGlobalBorlandMakefileGenerator.cxx @@ -71,12 +71,13 @@ std::vector cmGlobalBorlandMakefileGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 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 646dfffa89..a280b8123e 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.h +++ b/Source/cmGlobalBorlandMakefileGenerator.h @@ -59,7 +59,8 @@ protected: std::vector GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions = std::vector()) override; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 6433681632..156ecce8a5 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::GenerateBuildCommand( const std::string& /*unused*/, const std::string& /*unused*/, const std::string& /*unused*/, std::vector const& /*unused*/, - const std::string& /*unused*/, bool /*unused*/, int /*unused*/, - bool /*unused*/, std::vector const& /*unused*/) + const std::string& /*unused*/, int /*unused*/, bool /*unused*/, + const cmBuildOptions& /*unused*/, std::vector 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& 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 const& nativeOptions) { @@ -2053,9 +2056,9 @@ int cmGlobalGenerator::Build( std::string outputBuffer; std::string* outputPtr = &outputBuffer; - std::vector makeCommand = - this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, targets, - realConfig, fast, jobs, verbose, nativeOptions); + std::vector 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 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 2406798af4..a43d4a63b0 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 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 const& nativeOptions = std::vector()); @@ -248,7 +249,8 @@ public: virtual std::vector GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions = std::vector()); virtual void PrintBuildCommandAdvice(std::ostream& os, int jobs) const; diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index bf537b738a..5e51dd2f7d 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -510,7 +510,8 @@ std::vector cmGlobalGhsMultiGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions) { GeneratedMakeCommand makeCommand = {}; diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h index 9076e0e319..26ea3c70e6 100644 --- a/Source/cmGlobalGhsMultiGenerator.h +++ b/Source/cmGlobalGhsMultiGenerator.h @@ -9,6 +9,7 @@ #include #include +#include "cmBuildOptions.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmTargetDepend.h" @@ -87,7 +88,8 @@ protected: std::vector GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions = std::vector()) override; diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx index 1b406a6969..1a625cc686 100644 --- a/Source/cmGlobalJOMMakefileGenerator.cxx +++ b/Source/cmGlobalJOMMakefileGenerator.cxx @@ -63,7 +63,8 @@ std::vector cmGlobalJOMMakefileGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions) { std::vector 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 822974589b..332d1cf055 100644 --- a/Source/cmGlobalJOMMakefileGenerator.h +++ b/Source/cmGlobalJOMMakefileGenerator.h @@ -52,7 +52,8 @@ protected: std::vector GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions = std::vector()) override; diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx index 9f3d30eeb2..55748cfa60 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.cxx +++ b/Source/cmGlobalNMakeMakefileGenerator.cxx @@ -106,7 +106,8 @@ std::vector cmGlobalNMakeMakefileGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions) { std::vector 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 ca5b8d61b4..b3574ebf58 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.h +++ b/Source/cmGlobalNMakeMakefileGenerator.h @@ -58,7 +58,8 @@ protected: std::vector GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions = std::vector()) override; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 19c4ee3a21..5b85179ccb 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 const& targetNames, const std::string& config, - bool /*fast*/, int jobs, bool verbose, + int jobs, bool verbose, const cmBuildOptions& /*buildOptions*/, std::vector const& makeOptions) { GeneratedMakeCommand makeCommand; diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 84fc06c1cd..c619b2eb27 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 GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions = std::vector()) override; diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 0556540913..ab9ca5055e 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 const& targetNames, const std::string& /*config*/, - bool fast, int jobs, bool verbose, + int jobs, bool verbose, const cmBuildOptions& buildOptions, std::vector 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 94ee47633b..5157826c56 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -12,6 +12,7 @@ #include #include +#include "cmBuildOptions.h" #include "cmGeneratorTarget.h" #include "cmGlobalCommonGenerator.h" #include "cmGlobalGeneratorFactory.h" @@ -163,7 +164,8 @@ public: std::vector GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions = std::vector()) override; diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index d7bc05d64a..e9824fbcf4 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 cmGlobalVisualStudio10Generator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions) { std::vector 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 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 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 c8fd14975a..4977a845d0 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -43,7 +43,8 @@ public: std::vector GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions = std::vector()) 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 c72b10957d..91012dda49 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 const& targetNames, const std::string& config, - bool /*fast*/, int /*jobs*/, bool /*verbose*/, + int /*jobs*/, bool /*verbose*/, const cmBuildOptions& /*buildOptions*/, std::vector const& makeOptions) { // Select the caller- or user-preferred make program, else devenv. diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index d1fb8040c7..33f1063092 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -69,7 +69,8 @@ public: std::vector GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions = std::vector()) override; diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx index 3e2d92df73..fb2a8b6a6e 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.cxx +++ b/Source/cmGlobalWatcomWMakeGenerator.cxx @@ -65,12 +65,13 @@ std::vector cmGlobalWatcomWMakeGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 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 da39d3f5db..eb939341d7 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.h +++ b/Source/cmGlobalWatcomWMakeGenerator.h @@ -9,6 +9,7 @@ #include #include +#include "cmBuildOptions.h" #include "cmGlobalGeneratorFactory.h" #include "cmGlobalUnixMakefileGenerator3.h" @@ -57,7 +58,8 @@ protected: std::vector GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions = std::vector()) override; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index bc2a6f77d1..203addd247 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 const& targetNames, const std::string& config, - bool /*fast*/, int jobs, bool /*verbose*/, + int jobs, bool /*verbose*/, const cmBuildOptions& /*buildOptions*/, std::vector const& makeOptions) { GeneratedMakeCommand makeCommand; diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 5917db3135..ff6ffe8898 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -80,7 +80,8 @@ public: std::vector GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector 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 const& makeOptions = std::vector()) override; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 96dcf0bc27..89011a21c2 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 packageReferences; - if (cmValue vsPackageReferences = - this->GeneratorTarget->GetProperty("VS_PACKAGE_REFERENCES")) { - cmExpandList(*vsPackageReferences, packageReferences); - } + std::vector 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 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 79aa5e8d4b..8d777a33a9 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 72b26e1086..ef4e37beef 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 cmake::GetDebugConfigs() int cmake::Build(int jobs, std::string dir, std::vector targets, std::string config, std::vector 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 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 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 aee9c04f11..1187be571e 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 targets, std::string config, std::vector 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 00aafdc2cf..22fdcf88f0 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include +#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 = For multi-configuration tools, choose .\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 dd786b818c..6bea788cff 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 c7f318ceda..568907c754 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 b37c7709a5..2fe0407a2b 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 0000000000..d00491fd7e --- /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 0000000000..4811bea2f7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/build-invalid-package-resolve-arg-stderr.txt @@ -0,0 +1 @@ +^Usage: cmake --build +\[options\] \[-- \[native-options\]\] diff --git a/Tests/RunCMake/VsNugetPackageRestore/CMakeLists.txt b/Tests/RunCMake/VsNugetPackageRestore/CMakeLists.txt new file mode 100644 index 0000000000..d8200fca0a --- /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 0000000000..56920d920a --- /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 0000000000..d9ae85a6d2 --- /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 0000000000..681461f365 --- /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 0000000000..6a87d0a8b8 --- /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 0000000000..5569a2966e Binary files /dev/null and b/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.1.0.0.nupkg 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 0000000000..5526b7657d --- /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 0000000000..9a943a80f0 --- /dev/null +++ b/Tests/RunCMake/VsNugetPackageRestore/Repository/NuGetTestProject/1.0.0/nugettestproject.nuspec @@ -0,0 +1,11 @@ + + + + NuGetTestProject + 1.0.0 + CMake.org + false + Package to test automatic NuGet package restore. + NuGetTestProject built using CMake + + diff --git a/Tests/RunCMake/VsNugetPackageRestore/RunCMakeTest.cmake b/Tests/RunCMake/VsNugetPackageRestore/RunCMakeTest.cmake new file mode 100644 index 0000000000..625167c063 --- /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 0000000000..a0227df0f8 --- /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 0000000000..2e54c8fc5d --- /dev/null +++ b/Tests/RunCMake/VsNugetPackageRestore/nuget.config.in @@ -0,0 +1,7 @@ + + + + + + + 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 0000000000..d00491fd7e --- /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 0000000000..10f32932ee --- /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 0000000000..d00491fd7e --- /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 0000000000..4811bea2f7 --- /dev/null +++ b/Tests/RunCMake/VsNugetPackageRestore/vs-nuget-package-restore-wrong-stderr.txt @@ -0,0 +1 @@ +^Usage: cmake --build +\[options\] \[-- \[native-options\]\]