Skip to content

Use ProjectReferences in libs shared framework source projects #116772

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions docs/coding-guidelines/project-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,19 +151,17 @@ src\<Library Name>\tests - Contains the test code for a library.
## ref
Reference assemblies are required for any library that has more than one implementation or uses a facade. A reference assembly is a surface-area-only assembly that represents the public API of the library. To generate a reference assembly source file you can use the [GenAPI tool](https://www.nuget.org/packages/Microsoft.DotNet.BuildTools.GenAPI). If a library is a pure portable library with a single implementation it need not use a reference assembly at all. Instructions on updating reference sources can be found [here](https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/updating-ref-source.md).

In the ref directory for the library there should be at most **one** `.csproj` that contains the latest API for the reference assembly for the library. That project can contain multiple entries in its `TargetFrameworks` property. Ref projects should use `<ProjectReference>` for its dependencies.
In the ref directory for the library there should be at most **one** `.csproj` that contains the latest API for the reference assembly for the library. That project can contain multiple entries in its `TargetFrameworks` property.

### ref output
All ref outputs should be under

`bin\$(MSBuildProjectName)\ref\$(TargetFramework)`

## src
In the src directory for a library there should be only **one** `.csproj` file that contains any information necessary to build the library in various target frameworks. All supported target frameworks should be listed in the `TargetFrameworks` property.
In the src directory for a library there should be only **one** `.csproj` file that contains any information necessary to build the library for various target frameworks. All supported target frameworks should be listed in the `TargetFramework` or `TargetFrameworks` property.

All libraries should use `<Reference Include="..." />` for all their references to libraries that compose the shared framework of the current .NETCoreApp. That will cause them to be resolved against the locally built targeting pack which is located at `artifacts\bin\microsoft.netcore.app.ref`. The only exception to that rule right now is for partial facades which directly reference System.Private.CoreLib and thus need to directly reference other partial facades to avoid type conflicts.

Other target frameworks than .NETCoreApp latest (i.e. `netstandard2.0`, `net462`, `net8.0`) should use ProjectReference items to reference dependencies.
Libraries should use `ProjectReference` items to reference live dependencies.

### src\ILLink
Contains the files used to direct the trimming tool. See [ILLink files](../workflow/trimming/ILLink-files.md).
Expand Down
6 changes: 3 additions & 3 deletions eng/generators.targets
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
(
'$(DisableImplicitFrameworkReferences)' == 'true' and
(
'@(Reference->AnyHaveMetadataValue('Identity', 'System.Runtime.InteropServices'))' == 'true' or
'@(ProjectReference->AnyHaveMetadataValue('Filename', 'System.Runtime.InteropServices'))' == 'true' or
'@(ProjectReference->AnyHaveMetadataValue('Identity', '$(CoreLibProject)'))' == 'true'
)
)" />
Expand All @@ -38,7 +38,7 @@
'$(MSBuildProjectExtension)' == '.csproj' and
(
'$(DisableImplicitFrameworkReferences)' == 'true' and
'@(Reference->AnyHaveMetadataValue('Identity', 'System.Runtime.InteropServices'))' == 'true'
'@(ProjectReference->AnyHaveMetadataValue('Filename', 'System.Runtime.InteropServices'))' == 'true'
)" />
</ItemGroup>

Expand All @@ -49,7 +49,7 @@
</ItemGroup>

<!-- Use this complex item list based filtering to add the ProjectReference to make sure dotnet/runtime stays compatible with NuGet Static Graph Restore.
That is required as the EnabledGenerators condition checks on the Reference and ProjectReference items and hence can't be a property condition. -->
That is required as the EnabledGenerators condition checks on the ProjectReference items and hence can't be a property condition. -->
<ItemGroup Condition="'@(EnabledGenerators)' != ''">
<ProjectReference Include="$(LibrariesProjectRoot)System.Runtime.InteropServices\gen\Microsoft.Interop.SourceGeneration\Microsoft.Interop.SourceGeneration.csproj"
ReferenceOutputAssembly="false"
Expand Down
41 changes: 22 additions & 19 deletions eng/references.targets
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<Project>

<PropertyGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
<!--
Disable RAR from transitively discovering dependencies for references. This is required as we don't copy
Expand All @@ -14,34 +15,35 @@
</ProjectReference>
</ItemDefinitionGroup>

<!-- Set the corresponding CoreLib runtime configuration. -->
<ItemGroup Condition="'@(ProjectReference)' != ''">
<_coreLibProjectReference Include="@(ProjectReference->WithMetadataValue('Identity', '$(CoreLibProject)'))" />
<ProjectReference Update="@(_coreLibProjectReference)"
Private="false">
<ProjectReference Update="@(_coreLibProjectReference)">
<SetConfiguration Condition="'$(RuntimeFlavor)' == 'CoreCLR' and
'$(Configuration)' != '$(CoreCLRConfiguration)'">Configuration=$(CoreCLRConfiguration)</SetConfiguration>
<SetConfiguration Condition="'$(RuntimeFlavor)' == 'Mono' and
'$(Configuration)' != '$(MonoConfiguration)'">Configuration=$(MonoConfiguration)</SetConfiguration>
</ProjectReference>
<!-- If a CoreLib ProjectReference is present, make all P2P assets non transitive. -->
<ProjectReference Update="@(ProjectReference->WithMetadataValue('PrivateAssets', ''))"
PrivateAssets="all"
Condition="'$(IsSourceProject)' == 'true' and '@(_coreLibProjectReference)' != ''" />
</ItemGroup>

<!-- Make shared framework assemblies not app-local (non private). -->
<Target Name="UpdateProjectReferencesWithPrivateAttribute"
AfterTargets="AssignProjectConfiguration"
BeforeTargets="PrepareProjectReferences"
Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
('$(IsTestProject)' == 'true' or '$(IsTestSupportProject)' == 'true') and
'@(ProjectReferenceWithConfiguration)' != ''">
<ItemGroup>
<ProjectReferenceWithConfiguration PrivateAssets="all"
Private="false"
Condition="$(NetCoreAppLibrary.Contains('%(Filename);')) and '%(ProjectReferenceWithConfiguration.Private)' == ''" />
</ItemGroup>
</Target>
<!-- Mark shared framework assemblies as non-transitive (privateassets=all) and non app-local (private=false). -->
<ItemGroup Condition="'@(ProjectReference)' != '' and
'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
'$(TargetFrameworkVersion)' == 'v$(NetCoreAppCurrentVersion)'">
<_ProjectReferenceWithOriginalIdentity Include="@(ProjectReference)"
OriginalIdentity="%(Identity)" />
<_projectReferenceWithFilename Include="@(_ProjectReferenceWithOriginalIdentity->Metadata('Filename'))" />

<_projectReferenceExcludedWithFilename Include="@(_projectReferenceWithFilename)"
Exclude="@(NetCoreAppLibrary)" />
<_projectReferenceIncludedWithFilename Include="@(_projectReferenceWithFilename)"
Exclude="@(_projectReferenceExcludedWithFilename)" />

<ProjectReference Update="@(_projectReferenceIncludedWithFilename->Metadata('OriginalIdentity'))">
<PrivateAssets Condition="'%(PrivateAssets)' == ''">all</PrivateAssets>
<Private Condition="'%(Private)' == ''">false</Private>
</ProjectReference>
</ItemGroup>

<Target Name="ReplaceCoreLibSrcWithRefAssemblyForCompilation"
AfterTargets="FindReferenceAssembliesForReferences"
Expand All @@ -52,4 +54,5 @@
<ReferencePathWithRefAssemblies Include="@(_resolvedCoreLibProjectReference->Metadata('ReferenceAssembly'))" />
</ItemGroup>
</Target>

</Project>
1 change: 1 addition & 0 deletions eng/resolveContract.targets
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
<PropertyGroup>
<!-- Let GenFacades use roslyn from the toolset package as it loads sources which might require newer language features. -->
<GenFacadesUseRoslynToolsetPackagePath>true</GenFacadesUseRoslynToolsetPackagePath>
<GenFacadesReferencePathItemName>ReferencePathWithRefAssemblies</GenFacadesReferencePathItemName>
</PropertyGroup>

<!-- ##### GenAPI settings ##### -->
Expand Down
45 changes: 13 additions & 32 deletions eng/targetingpacks.targets
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<!--
The following properties need to be set for this logic to work correctly:
- ProductVersion
- NetCoreAppCurrent
- NetCoreAppCurrentVersion
- MicrosoftNetCoreAppFrameworkName
- MicrosoftNetCoreAppRefPackDir
- optional: MicrosoftNetCoreAppRuntimePackDir
- optional: AppHostSourcePath & SingleFileHostSourcePath
- optional: Crossgen2Dir
-->

<Project>
<!--
The following properties need to be set for this logic to work correctly:
- ProductVersion
- NetCoreAppCurrent
- NetCoreAppCurrentVersion
- MicrosoftNetCoreAppFrameworkName
- MicrosoftNetCoreAppRefPackDir
- optional: MicrosoftNetCoreAppRuntimePackDir
- optional: AppHostSourcePath & SingleFileHostSourcePath
- optional: Crossgen2Dir
-->

<PropertyGroup>
<LocalFrameworkOverrideName>$(MicrosoftNetCoreAppFrameworkName)</LocalFrameworkOverrideName>
<TargetingpacksTargetsImported>true</TargetingpacksTargetsImported>
Expand Down Expand Up @@ -90,26 +90,6 @@
Condition="'$(UseLocalAppHostPack)' == 'true' and '@(KnownAppHostPack->AnyHaveMetadataValue('TargetFramework', '$(NetCoreAppCurrent)'))' != 'true'" />
</ItemGroup>

<!-- Simple name references will be resolved from the targeting pack folders and should never be copied to the output. -->
<ItemGroup>
<Reference Update="@(Reference)">
<Private Condition="'%(Reference.Extension)' != '.dll'">false</Private>
</Reference>
</ItemGroup>

<!-- Add the resolved targeting pack to the assembly search path. -->
<Target Name="UseTargetingPackForAssemblySearchPaths"
BeforeTargets="ResolveAssemblyReferences;
DesignTimeResolveAssemblyReferences"
Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
'$(TargetFrameworkVersion)' == 'v$(NetCoreAppCurrentVersion)' and
'$(DisableImplicitFrameworkReferences)' == 'true'">
<PropertyGroup>
<AssemblySearchPaths>$(AssemblySearchPaths);$(MicrosoftNetCoreAppRefPackRefDir.TrimEnd('/\'))</AssemblySearchPaths>
<DesignTimeAssemblySearchPaths>$(DesignTimeAssemblySearchPaths);$(MicrosoftNetCoreAppRefPackRefDir.TrimEnd('/\'))</DesignTimeAssemblySearchPaths>
</PropertyGroup>
</Target>

<!-- Use local targeting/runtime pack for NetCoreAppCurrent. -->
<Target Name="UpdateLocalTargetingAndRuntimePack"
Condition="'$(UseLocalTargetingRuntimePack)' == 'true'"
Expand Down Expand Up @@ -197,4 +177,5 @@
<IlcFrameworkNativePath>$(BootstrapRuntimePackDir)/runtimes/$(TargetRid)/native/</IlcFrameworkNativePath>
<IlcSdkPath>$(BootstrapAotSdkDir)/</IlcSdkPath>
</PropertyGroup>

</Project>
11 changes: 10 additions & 1 deletion src/libraries/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
<UseLocalTargetingRuntimePack Condition="'$(IsNETCoreAppAnalyzer)' == 'true'">false</UseLocalTargetingRuntimePack>
<!-- By default, disable implicit framework references for NetCoreAppCurrent libraries. -->
<DisableImplicitFrameworkReferences Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
$([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '$(NETCoreAppCurrentVersion)')) and
'$(TargetFrameworkVersion)' == 'v$(NetCoreAppCurrentVersion)' and
('$(IsNETCoreAppRef)' == 'true' or '$(IsNETCoreAppSrc)' == 'true')">true</DisableImplicitFrameworkReferences>
<!-- Enable trimming for any source project that's part of the shared framework.
Don't attempt to trim PNSE assemblies which are generated from the reference source. -->
Expand Down Expand Up @@ -233,4 +233,13 @@
</ItemGroup>
</When>
</Choose>

<!-- Add a meaningless "-project" suffix to the package id for non-packable source projects.
NuGet uses PackageId regardless of whether the project is packable as the key for restore
graph project nodes. This is important so that NuGet doesn't get confused when a transitive
package reference and a project reference with the same key is in the graph. -->
<PropertyGroup>
<PackageId Condition="'$(IsSourceProject)' == 'true' and '$(IsPackable)' != 'true'">$(MSBuildProjectName)-project</PackageId>
</PropertyGroup>

</Project>
26 changes: 13 additions & 13 deletions src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -239,22 +239,22 @@
<Compile Include="Microsoft\CSharp\RuntimeBinder\ComInterop\VariantArray.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\ComInterop\VariantBuilder.cs" />

<Reference Include="System.Reflection.Emit" />
<Reference Include="System.Reflection.Emit.ILGeneration" />
<Reference Include="System.Reflection.Emit.Lightweight" />
<Reference Include="System.Reflection.Primitives" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Reflection.Emit\src\System.Reflection.Emit.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Reflection.Emit.ILGeneration\src\System.Reflection.Emit.ILGeneration.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Reflection.Emit.Lightweight\src\System.Reflection.Emit.Lightweight.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Reflection.Primitives\src\System.Reflection.Primitives.csproj" />
</ItemGroup>

<ItemGroup>
<Reference Include="System.Collections" />
<Reference Include="System.Collections.Concurrent" />
<Reference Include="System.Linq" />
<Reference Include="System.Linq.Expressions" />
<Reference Include="System.Memory" />
<Reference Include="System.ObjectModel" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.InteropServices" />
<Reference Include="System.Threading" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Collections\src\System.Collections.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Collections.Concurrent\src\System.Collections.Concurrent.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Linq\src\System.Linq.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Linq.Expressions\src\System.Linq.Expressions.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Memory\src\System.Memory.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.ObjectModel\src\System.ObjectModel.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Runtime\src\System.Runtime.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Runtime.InteropServices\src\System.Runtime.InteropServices.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Threading\src\System.Threading.csproj" />
</ItemGroup>

</Project>
Loading
Loading