-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Raise Transitive Project References to MSBuild elements #478
Conversation
…ojectReferences is called
…ojects with ProducesNoOutput settings. (Fixes failures building xUnit.net.csproj)
<Target Name="IncludeTransitiveProjectReferences" | ||
Condition="'$(ResolvePackageDependenciesForBuild)' == 'true' and '$(EnableResolvePackageDependencies)' == 'true' and Exists('$(ProjectAssetsFile)')" | ||
DependsOnTargets="_ComputeTransitiveProjectReferences" | ||
BeforeTargets="AssignProjectConfiguration"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BeforeTargets="AssignProjectConfiguration"
ensures ProjectReference
elements are created before they are processed into ResolvedProjectReferences. The alternative is to add this to the list ResolvePackageDependenciesForBuildDependsOn
, but that would result in IncludeTransitiveProjectReferences
being called too late.
Choosing this approach means we have to copy the condition from ResolvePackageDependenciesForBuild
to ensure we are not calling RunResolvePackageDependencies
at inappropriate times. (E.g. Without this condition, the sdk build fails on building xUnit.net.csproj
Another alternative is to bypass ResolveProjectReferences and generate the _ResolvedProjectReferencePaths
element directly, as is done in Microsoft.NuGet.targets. This currently does not work because of a bug calculating resolved paths (#479).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add IncludeTransitiveProjectReferences
to ResolvePackageDependenciesForBuildDependsOn
, and then put BeforeTargets="AssignProjectConfiguration"
on the ResolvePackageDependenciesForBuild
target? It seems like that would prevent us from having to repeat the same condition twice.
In any case, I would like to see comments in the targets file itself explaining how the ordering works. IIUC, the key is that the AssignProjectConfiguration
is the entry point that reads ProjectReference
items, so this target needs to run before that, but only if there is an assets file.
Separately, what is the difference between the ResolvePackageDependenciesForBuild
and EnableResolvePackageDependencies
properties? They seem to only be used together.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears the two flag properties are redundant, and may have been added separately. I've removed EnableResolvePackageDependencies
and also simplified the ordering as you suggested to avoid repeating the condition.
/cc @dotnet/project-system |
DependsOnTargets="RunResolvePackageDependencies" | ||
Returns="_TransitiveProjectReferences"> | ||
<ItemGroup> | ||
<ProjectDefs Include="@(PackageDefinitions->WithMetadataValue('Type', 'project'))" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Let's be consistent on not abbreviating things. We have PackageDefinitions and ProjectDefs on the same line here. It should be ProjectDefinitions.
Item names are also supposed to be singular, but that's one Microsoft has gotten wrong in many places so I feel less strongly about enforcing it. #Resolved
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<Version>42.43.44.45-alpha</Version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason these projects need to have a version? If not, let's remove them from the project file.
} | ||
|
||
[Fact] | ||
public void It_builds_the_project_successfully_twice() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.HaveStdOutContaining("This string came from AuxLibrary!"); | ||
|
||
var appInfo = FileVersionInfo.GetVersionInfo(Path.Combine(outputDirectory.FullName, "TestApp.dll")); | ||
appInfo.CompanyName.Should().Be("Test Authors"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My feeling is that we don't need to be testing the assembly versions and attributes here. Tests should generally be specific about what they are testing as opposed to testing a bunch of behaviors that don't seem to be related in a given scenario.
<Target Name="IncludeTransitiveProjectReferences" | ||
Condition="'$(ResolvePackageDependenciesForBuild)' == 'true' and '$(EnableResolvePackageDependencies)' == 'true' and Exists('$(ProjectAssetsFile)')" | ||
DependsOnTargets="_ComputeTransitiveProjectReferences" | ||
BeforeTargets="AssignProjectConfiguration"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add IncludeTransitiveProjectReferences
to ResolvePackageDependenciesForBuildDependsOn
, and then put BeforeTargets="AssignProjectConfiguration"
on the ResolvePackageDependenciesForBuild
target? It seems like that would prevent us from having to repeat the same condition twice.
In any case, I would like to see comments in the targets file itself explaining how the ordering works. IIUC, the key is that the AssignProjectConfiguration
is the entry point that reads ProjectReference
items, so this target needs to run before that, but only if there is an assets file.
Separately, what is the difference between the ResolvePackageDependenciesForBuild
and EnableResolvePackageDependencies
properties? They seem to only be used together.
BeforeTargets="AssignProjectConfiguration"> | ||
<ItemGroup> | ||
<!-- Add the references we computed --> | ||
<ProjectReference Include="@(_TransitiveProjectReferences)" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible for there to be a transitive reference from the assets file to a project that is also directly referenced? It would be good to have a test case to cover this, where B references C, and A references both B and C. #Resolved
…encies and remove redundant condition EnableResolvePackageDependencies
Use package dependencies (under "target") instead of package definitions (under "library") to compute transitive project references. Package dependencies could contain different information for different TFMs. This also simplifies determining which project references are transitive since we can do that all using information in the package dependency tree.
After chatting with @emgarten , I've made some changes. Previously we were computing transitive project references from Commit f3b057b changes to using PackageDependencies so computing transitive project references matches the information for the active target. This includes excluding projects marked with a placeholder compile time assembly Additionally I added logic to exclude directly referenced projects to address the concern @dsplaisted raised. It turns out these duplicated projects were deduped by I've tested this using the following project layout:
When building A:
I simulated making E a non-transitive reference in C, by modifying the assets file to insert a placeholder in E. With this change only C is treated as a transitive reference and E is not sent to the compiler. This compiles fine, but I get an error in the |
/cc @srivatsn for Ask Mode approval |
…ageDependencies task
Merging so we can get some insertions going. Additional feedback still welcome. |
When this fix will be available in VS 2017? |
It should already be in the latest RC of VS 2017. |
Any way I can opt out of this? Lets say, I have the following project layout. A -> B -> C. I don't want classes inside assembly C to be directly accessible inside assembly A. |
Adding PrivateAssets=All to the ProjectReference stops the flow of the transitive ref. So, in this case. B.csproj would have this: <ProjectReference Include="C.csproj" PrivateAssets="All" /> |
@srivatsn, you mean ProjectReference, right? |
Ah yes typo - fixed it the original comment. |
Thanks a lot.. Worked like a charm 👍 |
Turns out that the .NET SDK lifts transitive project references as direct references (without any additional metadata), and this causes the second-level dependency from being built unexpectedly (see dotnet/sdk#478 and dotnet/project-system#199). Since we don't want to disrupt the IDE (BuildingInsideVisualStudio) and we only want to fix this for the very specific case of running from the CLI `dotnet pack --no-build`, we make the fix very constrained for that scenario. We check for `NoBuild` but ALSO for `_IsPacking`, which is passed by the `dotnet pack` command. This ensures minimal impact in all other scenarios, since we're essentially turning off a built-in behavior in the SDK that has explicit side-effects (by design and desirable) and we should preserve. #Fixes 501
Turns out that the .NET SDK lifts transitive project references as direct references (without any additional metadata), and this causes the second-level dependency from being built unexpectedly (see dotnet/sdk#478 and dotnet/project-system#199). Since we don't want to disrupt the IDE (BuildingInsideVisualStudio) and we only want to fix this for the very specific case of running from the CLI `dotnet pack --no-build`, we make the fix very constrained for that scenario. We check for `NoBuild` but ALSO for `_IsPacking`, which is passed by the `dotnet pack` command. This ensures minimal impact in all other scenarios, since we're essentially turning off a built-in behavior in the SDK that has explicit side-effects (by design and desirable) and we should preserve. #Fixes 501
Turns out that the .NET SDK lifts transitive project references as direct references (without any additional metadata), and this causes the second-level dependency from being built unexpectedly (see dotnet/sdk#478 and dotnet/project-system#199). Since we don't want to disrupt the IDE (BuildingInsideVisualStudio) and we only want to fix this for the very specific case of running from the CLI `dotnet pack --no-build`, we make the fix very constrained for that scenario. We check for `NoBuild` but ALSO for `_IsPacking`, which is passed by the `dotnet pack` command. This ensures minimal impact in all other scenarios, since we're essentially turning off a built-in behavior in the SDK that has explicit side-effects (by design and desirable) and we should preserve. #Fixes 501
Raise closure of Transitive Project References to msbuild as
ProjectReference
elements. This closure is generated by NuGet in the assets file.Fixes #200
See dotnet/project-system#199 (comment) for details on P2P plan.