Improve project reference consistency#37338
Improve project reference consistency#37338dougbu merged 5 commits intodotnet:mainfrom dougbu:dougbu/reference.consistency
Conversation
- use `Private` and `SkipGetTargetFrameworkProperties` w/ `ReferenceOutputAssemblies="false"`
- correct meaningless `$(ReferenceOutputAssemblies)` settings; no such metadata
- `Private="false"` avoids unnecessary file copies
- `SkipGetTargetFrameworkProperties="true"` should reduce useless TFM negotiation
- that said, it can't be used everywhere due to multi-targeting restrictions
- do not use `PrivateAssets="All"` in `@(ProjectReference)` items or `@(Reference) items that become them
- has no meaning in `@(ProjectReference)` items
- add warnings about mixed-up application of `%(Private)` and `%(PrivateAssets)`
nit: make references _look_ consistent too e.g. use consistent attribute order and wrap lines
- should not be necessary
|
This may help w/ #32219 though consistency doesn't hurt in general 😄 @rainersigwald I'd appreciate your thoughts on the changes here and potential unintended consequences. For one thing, does |
There was a problem hiding this comment.
At least we got the spelling right, even if the metadata was ignored 😁
There was a problem hiding this comment.
ReferenceOutputAssembly="false" tells msbuild and NuGet not to include the reference in a generated .nuspec i.e. the PrivateAssets="All" intention was already in the references where I removed PrivateAssets="All"
There was a problem hiding this comment.
It's a nit but I'm tempted to make Microsoft.AspNetCore.App.Ref and Microsoft.AspNetCore.App.Runtime project reference providers and add errors when they're @(Reference)d w/o ReferenceOutputAssembly="false". That would get rid of some of these non-@(Reference) items but may require another special case or two. Thoughts❔
There was a problem hiding this comment.
Similarly, could make the .npmproj projects project reference providers for the same consistency reason as App.Ref and App.Runtime. Would be slightly less useful because these references are a bit less common and don't need additional special cases or warnings / errors.
- remove `SkipGetTargetFrameworkProperties="true"` from App.Ref reference to App.CodeFixes - need TFM negotiation when App.Ref builds on at least some platforms - firm up `net7.0` ➡️ `netstandard2.0` transition - fix typo in Rpm.TargetingPack.rpmproj - align Microsoft.AspNetCore.AzureAppServices.SiteExtension.csproj w/ Microsoft.AspNetCore.Runtime.SiteExtension.pkgproj - use same Microsoft.Web.Xdt.Extensions reference approach nit: remove extra Microsoft.AspNetCore.App.Analyzers references; brought in by App.CodeFixes
For another, is |
dougbu
left a comment
There was a problem hiding this comment.
We normally use SkipGetTargetFrameworkProperties="true" only when referring to .npmproj from .csproj projects, to .csproj from .debproj or .rpmproj projects, or between .csproj projects with identical (and single) TFMs. Highlighting the few exceptions…
Do any of these raise red flags for you @rainersigwald❔
| <Reference Include="Microsoft.AspNetCore.Mvc.Testing.Tasks" | ||
| Private="false" | ||
| ReferenceOutputAssembly="false" | ||
| SkipGetTargetFrameworkProperties="true" /> |
There was a problem hiding this comment.
TFM here is net7.0 while that in Microsoft.AspNetCore.Mvc.Testing.Tasks is netstandard2.0
| <ProjectReference Include="..\..\Framework\App.Ref\src\Microsoft.AspNetCore.App.Ref.csproj" | ||
| Condition=" $(IsTargetingPackBuilding) "> | ||
| <ReferenceOutputAssembly>false</ReferenceOutputAssembly> | ||
| <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties> | ||
| </ProjectReference> | ||
| Condition=" $(IsTargetingPackBuilding) " | ||
| Private="false" | ||
| ReferenceOutputAssembly="false" | ||
| SkipGetTargetFrameworkProperties="true" /> | ||
| <ProjectReference Include="..\..\Framework\App.Runtime\src\Microsoft.AspNetCore.App.Runtime.csproj" | ||
| Condition=" !$(IsTargetingPackBuilding) "> | ||
| <ReferenceOutputAssembly>false</ReferenceOutputAssembly> | ||
| <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties> | ||
| </ProjectReference> | ||
| Condition=" !$(IsTargetingPackBuilding) " | ||
| Private="false" | ||
| ReferenceOutputAssembly="false" | ||
| SkipGetTargetFrameworkProperties="true" /> | ||
| </ItemGroup> |
There was a problem hiding this comment.
TFM here is net462 while that in the App projects is net7.0
| <ProjectReference Include="..\..\Framework\App.Runtime\src\Microsoft.AspNetCore.App.Runtime.csproj"> | ||
| <ReferenceOutputAssembly>false</ReferenceOutputAssembly> | ||
| <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties> | ||
| </ProjectReference> | ||
| <ProjectReference Include="..\..\Framework\App.Runtime\src\Microsoft.AspNetCore.App.Runtime.csproj" | ||
| Private="false" | ||
| ReferenceOutputAssembly="false" | ||
| SkipGetTargetFrameworkProperties="true" /> |
There was a problem hiding this comment.
TFM here is net462 while that in the App.Runtime project is net7.0
| <Reference Include="GetDocument.Insider" | ||
| Private="false" | ||
| ReferenceOutputAssembly="false" | ||
| SkipGetTargetFrameworkProperties="true"> | ||
| <Targets Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">Publish</Targets> |
There was a problem hiding this comment.
This project and GetDocument.Insider both multi-target but their TFM sets are identical. But, this is the only case where this PR adds SkipGetTargetFrameworkProperties="true" to an "unusual" project and it seems to be working fine.
|
Alright I'll revert some or all of my second commit. To confirm my understanding, "handled natively" also means |
- keep using this metadata when referring to .npmproj projects
|
Unless I hear the following cases also need |
|
/ping reviewers Bringing general questions to the top
|
|
And, sorry, @rainersigwald but I had a couple more questions for you:
|
|
Note that while, at a glance, this change looks cosmetic, the typos ( |
I think so, because most of the ResolveProjectReference machinery doesn't pay attention to it. Mostly it just gets inherited by the eventual
It's definitely unusual but nothing scares me too much. |
😀 much appreciated @rainersigwald❕ /ping reviewers (especially the many code owners tagged). This PR is ready to go. |
Pilchie
left a comment
There was a problem hiding this comment.
Our build is complicated enough that I don't understand everything this is doing but the general idea seems sound.
However, one concern is that I thought MSBuild didn't block for ProjectReferences to build if they had ReferenceOutputAssembly="false". Since this sets that in more places, is it likely to actually introduce more build races? @rainersigwald do you know about the scheduling aspect?
Well, consistency should reduce the concept count a bit 😺
Hmm, I don't recall problems in this area except w.r.t. our .npmproj projects. We use |
It's actually the opposite: we continue to block on the build of the referenced projects in From the perspective of the project, the MSBuild task doesn't offer a fire-and-forget mode; it's always a synchronous wait. The node will yield the project and do other stuff, but the calling project is frozen until the requested projects/targets are done. |
I have vague memories of us trying this in the early days of Roslyn.sln and running into problems with it, but I definitely don't remember the details, and you know this space better than I. |
Improve project reference consistency
PrivateandSkipGetTargetFrameworkPropertiesw/ReferenceOutputAssemblies="false"$(ReferenceOutputAssemblies)settings; no such metadataPrivate="false"avoids unnecessary file copiesSkipGetTargetFrameworkProperties="true"should reduce useless TFM negotiationPrivateAssets="All"in@(ProjectReference)items or `@(Reference) items that become them@(ProjectReference)items%(Private)and%(PrivateAssets)Remove most
UndefinePropertiesuse