Skip to content

Improve project reference consistency #37338

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

Merged
merged 5 commits into from
Oct 14, 2021

Conversation

dougbu
Copy link
Member

@dougbu dougbu commented Oct 6, 2021

Improve project reference consistency

  • 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)

Remove most UndefineProperties use

  • should not be necessary

dougbu added 2 commits October 6, 2021 16:34
- 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
@dougbu dougbu requested review from rainersigwald, BrennanConroy and a team October 6, 2021 23:38
@dougbu
Copy link
Member Author

dougbu commented Oct 6, 2021

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 %(UndefineProperties) metadata on our @(Reference) items that turn into @(ProjectReference) items and "regular" @(ProjectReference) items work at all and potentially need to be restored in some of these cases❔

@@ -25,22 +25,19 @@
<ItemGroup>
<ProjectReference
Include="..\..\JSInterop\Microsoft.JSInterop.JS\src\Microsoft.JSInterop.JS.npmproj"
ReferenceOutputAssemblies="false"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least we got the spelling right, even if the metadata was ignored 😁

@@ -28,9 +28,8 @@
<!-- We include this here to ensure that the shared framework is built before we leverage it when running
the dev server. -->
<ItemGroup>
<ProjectReference
Include="$(RepoRoot)src\Framework\App.Runtime\src\Microsoft.AspNetCore.App.Runtime.csproj"
PrivateAssets="All"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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"

<ProjectReference
Include="$(RepoRoot)src\Framework\App.Runtime\src\Microsoft.AspNetCore.App.Runtime.csproj"
PrivateAssets="All"
<ProjectReference Include="$(RepoRoot)src\Framework\App.Runtime\src\Microsoft.AspNetCore.App.Runtime.csproj"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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❔

@@ -18,7 +18,11 @@
<Reference Include="Microsoft.Extensions.Logging" />
<Reference Include="Microsoft.JSInterop.WebAssembly" />

<ProjectReference Include="..\..\..\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj" ReferenceOutputAssemblies="false" SkipGetTargetFrameworkProperties="true" UndefineProperties="TargetFramework" Private="false" Condition="'$(BuildNodeJS)' != 'false' and '$(BuildingInsideVisualStudio)' != 'true'" />
<ProjectReference Include="..\..\..\Web.JS\Microsoft.AspNetCore.Components.Web.JS.npmproj"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
@dougbu dougbu force-pushed the dougbu/reference.consistency branch from ebfe559 to 248d2ab Compare October 7, 2021 05:32
@Pilchie Pilchie added the area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework label Oct 7, 2021
@dougbu
Copy link
Member Author

dougbu commented Oct 7, 2021

For one thing, does %(UndefineProperties) metadata on our @(Reference) items that turn into @(ProjectReference) items and "regular" @(ProjectReference) items work at all and potentially need to be restored in some of these cases❔

For another, is %(ProjectReference.Private) metadata ignored when %(ReferenceOutputAssembly) is false

Copy link
Member Author

@dougbu dougbu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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" />
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TFM here is net7.0 while that in Microsoft.AspNetCore.Mvc.Testing.Tasks is netstandard2.0

Comment on lines 27 to 37
<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>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TFM here is net462 while that in the App projects is net7.0

Comment on lines -34 to +40
<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" />
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TFM here is net462 while that in the App.Runtime project is net7.0

Comment on lines +27 to +31
<Reference Include="GetDocument.Insider"
Private="false"
ReferenceOutputAssembly="false"
SkipGetTargetFrameworkProperties="true">
<Targets Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">Publish</Targets>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@rainersigwald
Copy link
Member

For one thing, does %(UndefineProperties) metadata on our @(Reference) items that turn into @(ProjectReference) items and "regular" @(ProjectReference) items work at all and potentially need to be restored in some of these cases❔

UndefineProperties is one of the metadata that is handled natively in the MSBuild task. In this case I think they were useful, preventing inner-build TFs from propagating to the references. For instance in one of the binlogs from this PR build I see an .npmproj building with TargetFramework=net7.0. Might be best to leave it anywhere you have SkipGetTargetFrameworkProperties="true" ReferenceOutputAssembly="false".

@dougbu
Copy link
Member Author

dougbu commented Oct 7, 2021

UndefineProperties is one of the metadata that is [handled natively in the MSBuild task][native_task].

Alright I'll revert some or all of my second commit. To confirm my understanding, "handled natively" also means <MSBuild /> picks up and uses %(UndefineProperties) metadata from @(ProjectReference) items, @(_MSBuildProjectReferenceExistent) items, and similar❔

- keep using this metadata when referring to .npmproj projects
@dougbu
Copy link
Member Author

dougbu commented Oct 7, 2021

Unless I hear the following cases also need %(UndefineProperties) restored, I'm leaving those bits from 6acca56 alone

M       src/Framework/App.Ref/src/Microsoft.AspNetCore.App.Ref.csproj
M       src/Mvc/Mvc.Testing/src/Microsoft.AspNetCore.Mvc.Testing.csproj
M       src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.csproj

@dougbu
Copy link
Member Author

dougbu commented Oct 7, 2021

/ping reviewers

Bringing general questions to the top

  1. 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❔
  2. 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.

@dougbu
Copy link
Member Author

dougbu commented Oct 7, 2021

And, sorry, @rainersigwald but I had a couple more questions for you:

  1. is %(ProjectReference.Private) metadata ignored when %(ReferenceOutputAssembly) is false
  • I'm wondering if I should remove Private="false" everywhere we use ReferenceOutputAssembly="false" (and would if it's just excess verbiage)
  • Also curious whether Private="true" ReferenceOutputAssembly="false" on an item would mean "copy output assembly to my bin/ folder but don't reference it when compiling"
  1. [on SkipGetTargetFrameworkProperties="true" exceptions from the single TFM norm] Do any of these raise red flags for you @rainersigwald

@dougbu
Copy link
Member Author

dougbu commented Oct 8, 2021

Note that while, at a glance, this change looks cosmetic, the typos (%(PrivateAssets) and especially @(ReferenceOutputAssemblies)) are important and may be causing some part of our file-locking problems. Looking forward to reviews as well as thoughts on the questions above and not quite as far above

@rainersigwald
Copy link
Member

  1. is %(ProjectReference.Private) metadata ignored when %(ReferenceOutputAssembly) is false

I think so, because most of the ResolveProjectReference machinery doesn't pay attention to it. Mostly it just gets inherited by the eventual @(Reference) item that gets created, which then respects it. If you have ReferenceOutputAssembly=false that won't get created. However it's still considered here when copying files around, so it might have some impact. https://github.com/dotnet/msbuild/blob/bbb9655b007be6d079985f3a7ec14f5d82a18f64/src/Tasks/Microsoft.Common.CurrentVersion.targets#L4920

  1. [on SkipGetTargetFrameworkProperties="true" exceptions from the single TFM norm] Do any of these raise red flags for you @rainersigwald

It's definitely unusual but nothing scares me too much.

@dougbu
Copy link
Member Author

dougbu commented Oct 11, 2021

I think so

😀 much appreciated @rainersigwald

/ping reviewers (especially the many code owners tagged). This PR is ready to go.

Copy link
Member

@Pilchie Pilchie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

@dougbu
Copy link
Member Author

dougbu commented Oct 13, 2021

Our build is complicated enough

Well, consistency should reduce the concept count a bit 😺

I thought MSBuild didn't block for ProjectReferences to build if they had ReferenceOutputAssembly="false"

Hmm, I don't recall problems in this area except w.r.t. our .npmproj projects. We use ReferenceOutputAssembly="false" all over the place, mostly to ensure build order. The problem, if any, should get worse only in the ~5 projects where I fixed ReferenceOutputAssembl**ies**="false".

@rainersigwald
Copy link
Member

However, one concern is that I thought MSBuild didn't block for ProjectReferences to build if they had ReferenceOutputAssembly="false".

It's actually the opposite: we continue to block on the build of the referenced projects in ResolveProjectReferences, but don't do anything with the output (if you don't specify OutputItemType).

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.

@Pilchie
Copy link
Member

Pilchie commented Oct 13, 2021

It's actually the opposite: we continue to block on the build of the referenced projects in ResolveProjectReferences, but don't do anything with the output (if you don't specify OutputItemType).

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.

@dougbu dougbu merged commit c8a3c22 into dotnet:main Oct 14, 2021
@ghost ghost added this to the 7.0-preview1 milestone Oct 14, 2021
@dougbu dougbu deleted the dougbu/reference.consistency branch October 14, 2021 05:01
dougbu added a commit to dougbu/razor-compiler that referenced this pull request Nov 17, 2021
* Improve project reference consistency
  - 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

* Remove most `UndefineProperties` use
  - should not be necessary
  - but, keep using this metadata when referring to .npmproj projects

* !fixup! Fix build issues found on CI
  - 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

Commit migrated from dotnet/aspnetcore@c8a3c224e7e5
@github-actions github-actions bot locked and limited conversation to collaborators Dec 8, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-infrastructure Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants