dotnet / msbuild

The Microsoft Build Engine (MSBuild) is the build platform for .NET and Visual Studio.
https://docs.microsoft.com/visualstudio/msbuild/msbuild
MIT License
5.21k stars 1.35k forks source link

[Discussion] Clean up sln (VisualStudio solution) files #1730

Closed srivatsn closed 1 year ago

srivatsn commented 7 years ago

From @chrisaut on February 21, 2017 4:32

Now that the csproj files are somewhat clean, are there plans to similarly clean up .sln files?

A sample solution with just two projects looks like this today:

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26206.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coreDemo", "coreDemo\coreDemo.csproj", "{1A6AEDEC-9638-465A-9EEE-7CC718C12DED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "netStdLib", "netStdLib\netStdLib.csproj", "{EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}"
EndProject
Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
        Debug|Any CPU = Debug|Any CPU
        Debug|x64 = Debug|x64
        Debug|x86 = Debug|x86
        Release|Any CPU = Release|Any CPU
        Release|x64 = Release|x64
        Release|x86 = Release|x86
    EndGlobalSection
    GlobalSection(ProjectConfigurationPlatforms) = postSolution
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Debug|x64.ActiveCfg = Debug|x64
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Debug|x64.Build.0 = Debug|x64
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Debug|x86.ActiveCfg = Debug|x86
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Debug|x86.Build.0 = Debug|x86
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Release|Any CPU.Build.0 = Release|Any CPU
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Release|x64.ActiveCfg = Release|x64
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Release|x64.Build.0 = Release|x64
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Release|x86.ActiveCfg = Release|x86
        {1A6AEDEC-9638-465A-9EEE-7CC718C12DED}.Release|x86.Build.0 = Release|x86
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Debug|x64.ActiveCfg = Debug|x64
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Debug|x64.Build.0 = Debug|x64
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Debug|x86.ActiveCfg = Debug|x86
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Debug|x86.Build.0 = Debug|x86
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Release|Any CPU.Build.0 = Release|Any CPU
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Release|x64.ActiveCfg = Release|x64
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Release|x64.Build.0 = Release|x64
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Release|x86.ActiveCfg = Release|x86
        {EEE8E2FD-7DAF-4AAC-8A2C-8B5D4A159B56}.Release|x86.Build.0 = Release|x86
    EndGlobalSection
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
    EndGlobalSection
EndGlobal

I see 3 "sections": 1) Information about VS, which version created it and the minimum version 2) List or projects and their locations 3) Solution and ProjectConfigurationPlatforms

1) Is the VisualStudio stuff really needed? I regularly run into changes here when opening solutions in different versions, it creates a change for no apparent reason.

2) Can we get rid of the GUIDs for the project lists? Also the logical name (coreDemo, netStdLib) in addition to the csproj, can this just be infered for the probably 99.99% case when the two match?

3) I can't say much about the ConfigurationPlatform stuff, except that it looks messy. I feel like this should be pulled out somehow.

Since everything is going xml (....I know, I know), perhaps the format of the sln file should also be xml. A minimalistic solution could look something like this:

<Solution MinimumVisualStudioVersion="10.0.40219.1">
  <Projects>
    <Project Location="coreDemo\coreDemo.csproj" Type="netCoreConsole" ProjectConfigurationPlatforms="Default" />
    <Project Location="netStdLib\netStdLib.csproj" Type="netStandardLib" >
        <ProjectConfigurationPlatforms>
            <ConfigurationPlatform Configuration="Release" Platform="x64" />
            <ConfigurationPlatform Configuration="Release" Platform="x86" />
        </ProjectConfigurationPlatforms>
    </Project>
  </Projects>
  <SolutionConfigurationPlatforms>
    <ConfigurationPlatform Configuration="Release" Platform="x64" />
    <ConfigurationPlatform Configuration="Release" Platform="x86" />
  </SolutionConfigurationPlatforms>
</Solution>

A few things to note: The Project Type Guids ("FAE04EC0-301F-11D3-BF4B-00C04F79EFBC", at least that's what I think those are) are messy, if this is really needed by VS for some reason let's please make it a string that makes sense for humans ("netCoreConsole" in the example). We pull the ProjectConfigurations into the projects where they logically belong. Also, while at times custom platform/configurations are needed, most of the time people I think just use the default (x86/x64/Any CPU)/(Debug/Release). So we just make those the default. For the project list we could also do the filepattern thing (*/.csproj) but I feel like projects aren't added/removed often enough to warrant this, so perhaps being explicit here is the better choice.

I just want to start this issue so that a discussion can be started, I'm by no means an expert on this stuff.

Copied from original issue: dotnet/roslyn-project-system#1594

aolszowka commented 2 years ago

@carlosmunozrodriguez As a stop gap I'd point you to some of the tools I've created to help avoid merge conflicts by enforcing sorts on the SLN, you can put these in as a gate on your CI to prevent anyone from drifting once they're fixed https://github.com/dotnet/msbuild/issues/1730#issuecomment-671358983

Nirmal4G commented 2 years ago

@davidfowl

It is a HARD problem. But if the enterprises are asking and they are your paying customers, could you not spend the brain power here to finally solve this issue?

My thoughts... A pattern I see with @Microsoft atleast on the outside, is that their internal teams' request comes first, then the enterprises (_the paying ones_), then the partners, the implicit customers (_through other channels_) and finally the community. I'm not saying that this is bad but have a time limit for how a highly requested issue stays stale. Like 5years is more than enough for any high demand feedback to be on the backlog. ***The ask for VS IDE to 64-bit only happened because of the internal teams request not because of the user voice. It's been on connect, user voice, and finally Dev community but no one bothered to take it up but once the request comes from the internal team, lo behold VS becomes 64-bit.*** See this kind of behavior is what I hate about $MSFT. I know all the political and technical reasons behind these decisions but what can we do? Humans are biased and $MSFT is full of them. I'm one of those.

That said, some of the solutions here are interesting... Especially one with the existing MSBuild project schema is very interesting but certainly limited for some of the aspects that we use solutions today but overall I'm all for team XML/XAML. It's the language for declarative definitions.

As for the "PLAN", we could fix some of the long standing issues with sln writer as @aolszowka mentioned now. Then, we could introduce new Solution schema (either with XML or XAML; as XAML allows OOP) to not interfere with the Project schema. We could initially add features that covers the existing scenarios with solution files; so the migration would be 1:1 from sln files, then we can add more as the implementation and it's usage progresses with the customers.

We could affectionately call them slnx files.

davidfowl commented 2 years ago

A pattern I see with https://github.com/microsoft atleast on the outside, is that their internal teams' request comes first, then the enterprises (the paying ones), then the partners, the implicit customers (through other channels) and finally the community.

The internal teams would disagree with you.

A plan would be complete, what we have here set of suggestions. I would love to spend energy fixing this problem.

Nirmal4G commented 2 years ago

The internal teams would disagree with you.

First...,

What would you say, the order is based on your experience? OR if there is any order at all? (doubt it as I see from various places that people engage with $MSFT)

I would love to spend energy fixing this problem.

Thank you for your kind words. 😊

davkean commented 2 years ago

The ask for VS IDE to 64-bit only happened because of the internal teams request not because of the user voice. It's been on connect, user voice, and finally Dev community but no one bothered to take it up but once the request comes from the internal team, lo behold VS becomes 64-bit.

Being on the team involved in making VS 64-bit, this is not how this happened. This was heavily influenced by enterprise customers and telemetry. VS team knew exactly what we were going to gain (and lose - 64-bit wasn't free and had some perf loses that we had to make up elsewhere) based on our performance telemetry and insight when we made this decision. I've covered a few of these here: https://twitter.com/davkean/status/1438027241074561026 and https://twitter.com/davkean/status/1489477275192279043.

We all ("the VS team") want to fix the solution problem, its a matter of picking the right time to make this change. As the Visual Studio team, we avoid making many large scale architectural changes all at the same time. You'll be happy to know, that starting in 17.2, our 15-20 year old code that handles the solution has been rewritten in C#, which is a step towards modernizing this.

Nirmal4G commented 2 years ago

@davkean the first tweet is news to me but I had already read the 2nd one. It was certainly interesting. I learned a lot. Thanks for sharing.

Wasn't it because of Windows 11 (10.0.22000 weird versioning I know!) dropping 32-bit distribution? At least on the executive-level...!

You'll be happy to know, that starting in 17.2, our 15–20-year-old code that handles the solution has been rewritten in C#, which is a step towards modernizing this.

First of all, YAY. Then my ask is, will that be matched/merged/replaced with the implementation in MSBuild? @rainersigwald thoughts on this?

davkean commented 2 years ago

Wasn't it because of Windows 11 (10.0.22000 weird versioning I know!) dropping 32-bit distribution?

We already don't support installing on 32-bit build of Windows so these decisions are unrelated. WOW64 still exists and will be supported for many, many years into the future.

Most of that code is VS's implementation of the solution & interaction with VS. The solution reader/writer is a very small amount of code.

Nirmal4G commented 2 years ago

Most of that code is VS's implementation of the solution & interaction with VS. The solution reader/writer is a very small amount of code.

I was talking about only the parts that match MSBuild's. Disparate implementations are problematic and hard to maintain.

MagicAndre1981 commented 2 years ago

yes, please fix this, merging/trying to resolve conflicts a sln is a nightmare

ViktorHofer commented 2 years ago

Note that there's also an implementation in the dotnet/sdk for reading/writing sln files: https://github.com/dotnet/sdk/blob/main/src/Cli/Microsoft.DotNet.Cli.Sln.Internal/SlnFile.cs. Ideally, these different implementation would be merged and made available centrally (i.e. as a nuget package).

kasperk81 commented 2 years ago

You'll be happy to know, that starting in 17.2, our 15-20 year old code that handles the solution has been rewritten in C#, which is a step towards modernizing this.

i'd be more happy if you had invested that time on xml based sln format instead.

I mean a real well though out plan that discusses the multi year migration plan for .NET projects and C++.

that'll give enough time to gather feedback and work out of remaining corner cases.

davidfowl commented 2 years ago

remove experimental feature flag and deprecate the old format two releases after that

You mean support the old format forever.

Solutions files are old, and there have been attempts to replace them before. It's not impossible but its not the same as writing up a plan without knowledge of the implementation details (which I also don't know).

kasperk81 commented 2 years ago

until there is a 100% confidence that all old sln features are supported in new xml based sln, yes. similar to how old and new csproj, vbproj, fsproj formats are supported by VS simultaneously. for most of the users, it will not come as a surprise at this point.

preferably with diagnostics on first-time solution load (backed by a sentinel file), a popup with a message: "Loading old-style .sln file. Do you want to upgrade to new format? Yes | No". in future version, when new format has some mileage and tools are caught up, replace "No" option with "Close", make it the mandatory to upgrade and delete the old (https://github.com/microsoft/slngen based?) implementation from VS source code. as-if it never existed, Γ  la how project.json / xproj formats were "phased out".

Hu1buerger commented 2 years ago

I do agree. The configuration should be readable by a human without any tooling. IMHO the team at google with dart did a fantastic job. Their configuration file is aweasome. I would love to use their syntax with .net

vrubleg commented 2 years ago

@Hu1buerger how does it look like in Dart?

Hu1buerger commented 2 years ago

@vrubleg take a look at this doc. And for a "live" example chosen at random by me see here.

The hole xml thing might me aweasome for the machine, but my brain likes to read a configuration that lists the important stuff, like dependencies, tooling, paths and so on. I do like the conditional features that the csproj brings, but i do not want to need to consult the documentation as i am changing the config - or need to use a tool to do that.

TL;DR: Darts config reads more like human text.

kasperk81 commented 2 years ago

yes yaml is best for configurations, hands down! azure devops configurations, github ci and many other systems use yaml and those configs are fun to work with. BUT yaml is technically not feasible unfortunately. msbuild is tied to xml serialization.

it is not perfect, but the modern project formats are concise, human readable and user can easily write it by hand (usually 5-20 lines for average project). if sln is switched to xml representation, majority of the community will be happy. something similar to: https://github.com/dotnet/msbuild/issues/1730#issuecomment-422169541.

vrubleg commented 2 years ago

Please, no YAML, it is a horrible format. Something like TOML would be much better, but it is also an alien format for MSBuild. The most logical and conforming way is to make it XML-based.

MagicAndre1981 commented 2 years ago

. if sln is switched to xml representation, majority of the community will be happy.

someone tried to do it in xml:

.Subsln files are used by SubSolution tools to describe the content of Visual Studio solutions in a user-friendly syntax.

<Subsln xmlns="http://subsln.github.io/">
    <Root>
        <Folder Name="Tools">
            <Files Path="tools/*.bat" />
        </Folder>
        <Folder Name="Tests">
            <Projects Path="**/*.Tests.csproj" />
        </Folder>
        <Projects Path="src/">
    </Root>
</Subsln>

VS2022 extension: https://marketplace.visualstudio.com/items?itemName=ReMinoer.SubSolution2022 VS2019 extension: https://marketplace.visualstudio.com/items?itemName=ReMinoer.SubSolution2019

gulshan commented 2 years ago

XAML?

workgroupengineering commented 1 year ago

@NickCraver a workaround you could use for your case today is to customize MSBuild's view of the solution when it builds from the command line (as in dotnet build).

You can do this with a solution build customization. Since your solution is MiniProfiler.sln, create a file named after.MiniProfiler.sln.targets that manipulates the ProjectReference item before MSBuild starts building things:

<Project InitialTargets="RemoveIncompatibleProjectsFromDotnetCoreBuild">
  <Target Name="RemoveIncompatibleProjectsFromDotnetCoreBuild"
          Condition="'$(MSBuildRuntimeType)' == 'Core'">
    <ItemGroup>
      <!-- These projects don't successfully build in `dotnet build`, so don't build them
          when MSBuild is running on Core. -->
      <ProjectReferenceToAvoidInDotnetBuild Include="samples\Samples.Mvc5.EFCore\Samples.Mvc5.EFCore.csproj" />
      <ProjectReferenceToAvoidInDotnetBuild Include="samples\Samples.Mvc5\Samples.Mvc5.csproj" />

      <ProjectReference Remove="@(ProjectReferenceToAvoidInDotnetBuild->'%(FullPath)')" />
    </ItemGroup>
  </Target>
</Project>

Hi, Tried in VS 17.4.4, seems like this behavior is no longer supported. Are there alternatives?

rainersigwald commented 1 year ago

@workgroupengineering please be specific about what you tried and how it didn't work; there should be no changes in that behavior.

workgroupengineering commented 1 year ago

I'm trying to run dotnet-format before the build starts whether it's launched from dotnet cli, visual studio, rider, etc.. .

rainersigwald commented 1 year ago

This is best tracked as a Visual Studio feature suggestion. The best one that I know of is https://developercommunity.visualstudio.com/t/Clean-up-sln-VisualStudio-solution-fil/988209.

If Visual Studio changes the solution format, MSBuild would follow.

Edit 9/24: Updated link from @chrisaut below that is better. My link https://developercommunity.visualstudio.com/t/Open-MicrosoftBuildTraversal-project-f/1371244 is one possible replacement but not exactly the same. Thanks!

chrisaut commented 1 year ago

https://developercommunity.visualstudio.com/t/Clean-up-sln-VisualStudio-solution-fil/988209

This is the direct equivalent, as of Aug 9, 2023 it's status has been changed to "On Roadmap"

am11 commented 5 months ago

I'm gonna lobby for .slnx here!

You succeeded! https://www.youtube.com/watch?v=wzMMclD8QsI πŸ˜‰

NickCraver commented 5 months ago

Hey @rainersigwald should we change the status of this - or is there another issue tracking it? (couldn't find in search)

thomaslevesque commented 5 months ago

See the discussion on Developer Community, though.

While it is really nice to see a progress with the preview of slnx in VS 2022 V 17.10.0 Preview 3.0, It comes as a significant disappointment that this solution might not be based on MSBuild (similar to traversal projects)

To handle the complexity of enterprise builds, it is critical that we are able to express similar MSBuild capabilities like conditionals, imports of other target files, target/tasks execution (e.g to automate some tasks when working with several projects), shared/transfer of properties to projects…

We should be able to express in a very similar compact form what is demonstrated in the slnx preview with a MSBuild approach. Currently, MSBuild has to translate sln into a meta MSBuild project and we should avoid that step entirely (which slnx would not avoid).

So, please, reconsider the usage of a MSBuild approach to express such slnx similar to what we have been already able to use with traversal projects.

rainersigwald commented 5 months ago

The Microsoft MSBuild team is involved in the internal discussions and trying to guide the effort, and of course MSBuild will adapt to deal with what what we settle on, but that's not quite set yet so no additional concrete MSBuild work.

ViktorHofer commented 5 months ago

I agree with @xoofx that being able to express dependencies via msbuild conditions is something that we need. Many of our own repositories would immensely benefit from this, especially the VMR effort.

kasperk81 commented 5 months ago

i'm just glad that guids are gone which fixes long standing issues like https://github.com/dotnet/project-system/issues/1821

am11 commented 5 months ago

@rainersigwald, thank you for the update. I have to admit that I don't have details about why Classic C# vs. C# distinction is needed at the solution level, but if/when slnx processing is integrated with MSBuild, it may be possible to unify the Type to just C# in solution and let SDK distinguish between the two if it's necessary (which it already seems to do around static evaluation of properties like UsingMicrosoftNETSdkWeb, without any help from sln context).

rainersigwald commented 5 months ago

why Classic C# vs. C# distinction is needed at the solution level

That detail is not relevant to MSBuild; it helps Visual Studio decide which project system to initialize for the specific projects (there are two, https://github.com/dotnet/project-system and an older closed-source one that's used for non-.NET-SDK projects).

nvmkpk commented 5 months ago

That detail is not relevant to MSBuild; it helps Visual Studio decide which project system to initialize for the specific projects (there are two, https://github.com/dotnet/project-system and an older closed-source one that's used for non-.NET-SDK projects).

Why is that attribute even required? VS should be able to read the first line (or few lines) and determine which project system to use right?

huoyaoyuan commented 5 months ago

VS should be able to read the first line (or few lines) and determine which project system to use right?

I believe it's not possible to correctly handle every case without do a full xml deserialization, or even loading a full MSBuild to evaluate it. MSBuild projects are quite flexibie.

Mrxx99 commented 5 months ago

VS should be able to read the first line (or few lines) and determine which project system to use right?

I believe it's not possible to correctly handle every case without do a full xml deserialization, or even loading a full MSBuild to evaluate it. MSBuild projects are quite flexibie.

But what's strange is I created a slnx from a solution (.NET 8 Avalonia projects + xUnit). It wrote all projects without the attribute, except the xUnit one which had "Classic C#". I removed that attribute and it still worked without difference.

Another thing I noticed globbing (*.csproj or for solution items) did not work.

rainersigwald commented 5 months ago

VS should be able to read the first line (or few lines) and determine which project system to use right?

I believe it's not possible to correctly handle every case without do a full xml deserialization, or even loading a full MSBuild to evaluate it. MSBuild projects are quite flexibie.

But what's strange is I created a slnx from a solution (.NET 8 Avalonia projects + xUnit). It wrote all projects without the attribute, except the xUnit one which had "Classic C#". I removed that attribute and it still worked without difference.

Another thing I noticed globbing (*.csproj or for solution items) did not work.

Please submit this kind of feedback to the VS team via VS Feedback!

davkean commented 5 months ago

Hey folks, I'm the VS team. The "Classic C#" is just a point in time issue and we'll fix this in a future update to the format. This is a similar case to what's called out on https://github.com/dotnet/project-system/issues/1821, but we've come up with a solution to resolve this.

charlesroddie commented 3 months ago

This is best tracked as a Visual Studio feature suggestion.

We are very interested in this but only as a dotnet feature not as a Visual Studio-specific feature.

slnx is currently supported in Visual Studio but not Visual Studio for Mac and not Rider.

This implies that slnx doesn't work in cross-platform projects.

The current Rider status is https://youtrack.jetbrains.com/issue/RIDER-110777 from a month ago:

The new format is currently in preview, likely to change, and more importantly, undocumented. Microsoft have not been in touch about this, so we have no sight of changes or timelines. Once Microsoft has shared details with the rest of the dotnet ecosystem, we'll be in a better position to update about Rider support.

Can I ask therefore: is this format now documented and communicated to developers of clients other than VS?

kasperk81 commented 3 months ago

Visual Studio for Mac

is retiring in august https://learn.microsoft.com/en-us/visualstudio/mac/what-happened-to-vs-for-mac

MikeRosoft commented 3 months ago

It's a positive change, but at the same time a disappointing one. (See announcement.) It seems that Microsoft has decided not to turn the solution file into a proper MsBuild file, but instead invented a specific XML format for the solution file.

kasperk81 commented 3 months ago

if slnx parser in visual studio is using dotnet, it can depend on msbuild evaluation engine package for Condition= support without invoking the real msbuild

flip side is dumb solution files (as they ever were) keep parser implementation efficient and user expectations in check

huoyaoyuan commented 3 months ago

is this format now documented and communicated to developers of clients other than VS?

The feature is highly incomplete and work in progress. We still need to wait for some time for announcement of it.

andremarcondesteixeira commented 2 months ago

I only ask myself one simple question: How can a feature not be implemented after 20 YEARS of the community continually asking for it?