Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a custom SDK resolver #2278

Open
natemcmaster opened this issue Jul 11, 2017 · 14 comments
Open

Adding a custom SDK resolver #2278

natemcmaster opened this issue Jul 11, 2017 · 14 comments
Labels

Comments

@natemcmaster
Copy link
Contributor

Problem
The default SDK resolver loading only looks for resolvers in $(MSBuildToolsDirectory32)/SdkResolvers (source).

Most of the time, this path is going to be C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\SdkResolvers. Writing files here requires admin permissions.

My scenario: I'm looking for a way to share a common set of targets and props across ASP.NET Core's 500+ csproj files, which are scattered among repos. We've tried PackageReference, but continually run into limitations. I've written and tested a custom SDK resolvers. It seems promising, but there is no easy way to make this available for MSBuild for VS and dotnet.exe without getting elevated permissions to write into the VS folder and/or C:\Program Files\dotnet folder.

Request
Provide a way to register custom SDK resolvers without needing to write into the MSBuild tools folder.

Ideas

  • Similar to <UsingTask>, add <UsingSdkResolver> directive that takes an assembly path.
  • Add another search path, such as $(MSBuildUserExtensionsPath)/$(MSBuildRuntimeType)/SdkResolvers
@clairernovotny
Copy link
Member

I would like to use this to make it easier to add support for other project types, like Rust. Ideally, a directory level configuration could point to a path containing an SDK. It'd work like directory.build.props where parent dirs are searched. I'd put that along the solution file.

Also, there should be a way (NuGet?) to distribute sdks. The aforementioned config file could point to a NuGet package with an SDKs folder in it, then it'd be automatically downloaded and added to the search path.

Then something like Visual Rust can package its targets as an SDK and distribute it on NuGet.

@dasMulli
Copy link
Contributor

@onovotny fyi there is an issue for a NuGet resolver at NuGet/Home#5220

@clairernovotny
Copy link
Member

@dasMulli Thanks for the pointer!

My ask when designing this feature is that it's not tied to .NET. That is, it should ideally support any project type that uses CPS to enable it to have its own SDK. The example I'm thinking of right now is Rust, but it can apply to any other language/platform.

@natemcmaster
Copy link
Contributor Author

Another example of the need for this: it's impossible to know of all possible installations of MSBuild. For example, OmniSharp (what powers VS Code) bundles the MSBuild runtime, which means the MSBuild folder and SdkResolver lookup path is %USERPROFILE%\.vscode\extensions\ms-vscode.csharp-1.12.0-beta4\bin\omnisharp\msbuild\SdkResolvers.

@AArnott
Copy link
Contributor

AArnott commented Oct 6, 2017

I would very much like to define a repo-level SDK for some project types that are custom to our repo. If MSBuild would be willing to search for SDKs similar to how @onovotny described, that would be awesome.

@japj
Copy link

japj commented Nov 4, 2017

Would it be possible for MSBuildSDKsPath to behave like PATH in that you can have multiple paths to sdk folders (already on disk). MSBuildSDKsPath can be overridden by environment if I understood correctly

@japj
Copy link

japj commented Nov 4, 2017

After reading some more of the discussions, it might be good to mention that for us it makes sense if a source tree can actually contain their own SDK(s) in the actual tree.

Having something like searching in the parent folders for an SDK config file would also help deployment on both developers and build machines, since they retrieve the source tree anyway.

I guess the resolver API would allow one to write a vs extension that actually scans parent folders for an SDK config file, but when I install this as a VS extension, will it also work from command line msbuild?

@TFTomSun
Copy link

TFTomSun commented Nov 4, 2017

Would like to throw in my two cents, how I do the target resolution up to now:

<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Smart.targets))\Smart.targets" />
That is pure MSBuild, no VS extension required.

That Smart.targets file is located in the root folder of a branch / workspace and redirects to other targets that belong to my build framework. From what I understood up to now, the SDK stuff is nothing else than two imports of a props and target file. So I think you could probably do something similar like I do or bake it directly into MSBuild as a default sdk resolver.

The advantage is, whenever you want to change the build behavior for some projects under a specific folder you can simply throw a Smart.targets file in their parent folder and it will be automatically taken. Another advantage is of course that it doesn't matter where your projects are located, there is no relative path that needs to be updated.

@dasMulli
Copy link
Contributor

dasMulli commented Nov 5, 2017

Auto-import of props/targets file already exists - Directory.Build.props / .targets files in the directory hierarchy will automatically be imported.

The SDK feature is mostly about re-using shared logic so I don't think it will be common to add SDKs to a repo (but maybe if you have 3 different types of project and want 3 different imports..).

Would it be possible for MSBuildSDKsPath to behave like PATH in that you can have multiple paths to sdk folders (already on disk).

This is actually a good idea and could be used as quick-fix for problems like https://github.com/dotnet/cli/issues/6178 where some SDKs are only distributed in VS but you'll want the main SDKs to be loaded from the CLI folder and only fall back to a VS path. (current solution is to copy the SDK folder). Could also be MSBuildAdditionalSDKsPath / MSBuildFallbackSDKsPath..

@TFTomSun
Copy link

TFTomSun commented Nov 5, 2017

@dasMulli wow, thanks for the hint regarding the auto-import. That will help me alot. Is that already working in VS 2015/MSBuild 14 or has it been introduced with VS 2017 / MSBuild 15 ?

@dasMulli
Copy link
Contributor

dasMulli commented Nov 5, 2017

That feature is new in MSBuild 15 / VS 2017

@sharwell
Copy link
Member

sharwell commented Dec 3, 2017

This issue is causing periodic problems for Roslyn contributors. While the .NET SDK gets installed into the expected directory, Roslyn always relies on a particular version of the SDK for reasons that vary over time. We would like the ability to restore the SDK itself as part of our Restore.cmd script, and have that SDK get resolved automatically as part of both build and IDE scenarios.

Leveraging this functionality will improve our ability to engage and retain external contributors by improving "pit of success" approach to development. Eventually we would like the complete restore process to happen inside Visual Studio (if/when necessary with minimal overhead), but until we reach that point a reasonable approach is Clone/Restore.cmd/Open solution. Until this feature is implemented, we are left with an unfortunate "manually installed things" step.

@dasMulli
Copy link
Contributor

dasMulli commented Dec 3, 2017

An orthogonal issue for these dev scenarios is probably support for a relative path in global.json (I can't find the issue now, I thought there was one in core-setup..).
That way a custom restore script could download a package into e.g. a .dotnet-cli folder and that version would then be used provided a global.json would point to that folder.

@jaredpar
Copy link
Member

jaredpar commented Dec 4, 2017

Leveraging this functionality will improve our ability to engage and retain external contributors by improving "pit of success" approach to development

Indeed. As the design stands now it's relatively easy to setup the command line build for a repo to "just work". Go up to dotnet/roslyn, clone run Restore.cmd then Build.cmd and everything will "just work". The build can fully bootstrap all of the needed components even on a clean Windows machine.

However the same is simply not true for the Visual Studio based experience. Open Roslyn.sln, Build and you're likely to be hit with an error message from our build

The 2.2.0 SDK is required to build this repo. It can be install here https://dotnetcli.blob.core.windows.net/dotnet/Sdk/2.2.0-preview1-007622/dotnet-sdk-2.2.0-preview1-007622-win-x64.exe

That's really unfortunate and frankly confusing to our users. Why is building from the command line possible when building from Visual Studio fails?

we are left with an unfortunate "manually installed things" step

Indeed. Worse is that it requires installing as "admin". Outside the initial VS install it shouldn't be necessary to use admin to build any repo. It's generally a sign that we need to be more easily extensible.

jeffkl added a commit that referenced this issue Jan 10, 2018
An SDK resolver that activates only when a user has specified a version.  This resolver is ordered to come before the DotNetSdkResolver but if a user does not specify a version (the default), then the NuGet SDK resolver is skipped.

The NuGet SDK resolver can be disabled with an environment variable just in case its causing issues or a user wants to override its functionality.

NuGet assemblies are loaded at runtime from their installed location.  They either come come [VisualStudioInstallRoot\Common7\IDE\CommonExtensions\Microsoft\NuGet or next to MSBuild.exe.  There is also an environment variable that can be set to specify a folder to use instead.

I've also placed references to NuGet into private subclasses so that assemblies are not loaded unless they are needed.  This means that if you have no version specified and no `global.json` with versions, `Newtonsoft.Json` and `NuGet.*.dll` are not loaded.  You only pay JIT penalty if you're using the functionality and hopefully we'll make up that time later in the build through caching.

Addresses item 6 in #2803 
Related to #2278
@AR-May AR-May added the triaged label Feb 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants