-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
ProjectReference: How to make one project to consume/import assets (content, props, targets) from another project? #5797
Comments
Team Triage: You can't do this with The problem here is that each project gets evaluated at the same time, and the outputs of your first project will not have generated such that your second project (at evaluation time) sees them. We also don't know where the outputs of a project are until build time. But in order to import and affect the second project we would need an import statement pointing to those outputs. |
Can you give more details? Also what is happening when I write |
Hey, I've also stumbled across this, I've been wanted to change our project / nuget to start using BuildTransitive, but it seems that those will not take into account in project references. In most places, you do both, its not one or the other, is there some sort of solution/workaround? Example: Project C reference project A I expected both A and C projects to receive BuildTransitive .prop files |
See #1054 (comment), there's a property that allows you to copy Content items transitively. It's not possible for MSBuild to get .props and .targets from project references though. The issue is that MSBuild needs to first import these props and targets before it can start parsing your project. And so everything is imported by the time that a project reference is being looked at. Closing the issue, feel free to ask more questions though! @yfital See the link above for copying over items from transitive project references. Copying over a nupkg that's a |
Related: NuGet/Home#6624
It's possible when you declare the imports to these props and targets in the first restore evaluation pass. NuGet does this to import props and targets files from nuget packages. The evaluation kicked-off by NuGet restore doesn't include those as NuGet then creates import files to import for subsequent evaluations: nuget.g.props and nuget.g.targets. As we already support this for PackageReferences, I don't see a strong reason why we couldn't do the same for ProjectReferences. That said, this might make more sense to fix on the NuGet side which is the component that triggers those separate restore evaluations. |
@ViktorHofer I don't understand. How can restore import files that don't exist? If we wait for them to exist then it's not exactly restore any more. |
Based on the issue description I would expect those asset files (i.e. props and targets under a build / buildTransitive) folder to already exist. Do you mean the generated import files? NuGet creates those as part of the restore run, i.e. nuget.g.props and nuget.g.targets which are then getting imported by subsequent evaluations. |
I'm thinking of the copies of those files in the output folder, which may not match the ones that are available at restore time, depending on a variety of details. |
I have the same problem of referencing project as if it was a NuGet package (aka reference its I come up with the following workaround to generate <!-- Directory.Solution.targets -->
<Project>
<!--
This target is used to redirect to project-spesific restore targets on solution-level restore.
-->
<Target Name="ImportProjectReferenceBuildFiles" AfterTargets="Restore">
<MSBuild Projects="@(ProjectReference)" Targets="Restore" />
</Target>
</Project> <!-- Directory.Build.targets -->
<Project>
<!--
This target is designed to gather information about referenced projects and generate import statements for .props and .targets files.
It uses `MSBuildProjectExtensionsPath` auto import feature like NuGet does to import the generated .props file.
-->
<Target
Name="ImportProjectReferenceBuildFiles"
BeforeTargets="Restore;BeforeBuild"
Inputs="@(ProjectReference);$(MSBuildThisFileFullPath)"
Outputs="$(MSBuildProjectExtensionsPath)\$(MSBuildProjectName).csproj.proj.g.props;$(MSBuildProjectExtensionsPath)\$(MSBuildProjectName).csproj.proj.g.targets"
>
<!-- Collecting .props and .targets files for the ProjectReferences -->
<ItemGroup>
<!-- Check for .props files in the build directory of the ProjectReferences -->
<_Props Include="@(ProjectReference->'%(RootDir)%(Directory)build\%(Filename).props')" Condition="Exists('%(RootDir)%(Directory)build\%(Filename).props')" />
<!-- Check for .targets files in the build directory of the ProjectReferences -->
<_Targets Include="@(ProjectReference->'%(RootDir)%(Directory)build\%(Filename).targets')" Condition="Exists('%(RootDir)%(Directory)build\%(Filename).targets')" />
</ItemGroup>
<!-- Creating groups to hold the XML content for import statements -->
<ItemGroup Condition="@(_Props) != '' or @(_Targets) != ''">
<_Lines Include="<Project>" />
</ItemGroup>
<ItemGroup>
<!-- Include for .props files -->
<_PropsLines Include="<Project>" />
<_PropsLines Include="<Import Project='" Condition="@(_Props) != ''" />
<_PropsLines Include="@(_Props->'%(Identity);')" Condition="@(_Props) != ''" />
<_PropsLines Include="' />" Condition="@(_Props) != ''" />
<_PropsLines Include="</Project>" />
</ItemGroup>
<ItemGroup>
<!-- Include for .targets files -->
<_TargetsLines Include="<Project>" />
<_TargetsLines Include="<Import Project='" Condition="@(_Targets) != ''" />
<_TargetsLines Include="@(_Targets->'%(Identity);')" Condition="@(_Targets) != ''" />
<_TargetsLines Include="' />" Condition="@(_Targets) != ''" />
<_TargetsLines Include="</Project>" />
</ItemGroup>
<ItemGroup Condition="@(_Props) != '' or @(_Targets) != ''">
<_Lines Include="</Project>" />
</ItemGroup>
<!-- Write the collected props and targets imports to a file -->
<WriteLinesToFile File="$(MSBuildProjectExtensionsPath)\$(MSBuildProjectName).csproj.proj.g.props" Lines="@(_PropsLines)" Overwrite="true" />
<WriteLinesToFile File="$(MSBuildProjectExtensionsPath)\$(MSBuildProjectName).csproj.proj.g.targets" Lines="@(_TargetsLines)" Overwrite="true" />
</Target>
<!--
Because most IDEs do not reload the project file up until after it has been modified, we need to force a reload of the project file by making a dummy change to it.
-->
<Target Name="ForceProjectReload" AfterTargets="ImportProjectReferenceBuildFiles">
<Touch Files="$(MSBuildProjectFullPath)">
<Output TaskParameter="TouchedFiles" ItemName="FilesTouched"/>
</Touch>
</Target>
</Project> |
Here's somewhat improved version to perform <Project>
<!--
This target is designed to gather information about referenced projects and generate import statements for .props and .targets files.
It uses `MSBuildProjectExtensionsPath` auto import feature like NuGet does to import the generated .props file.
-->
<Target
Name="ImportProjectReferenceBuildFiles"
BeforeTargets="Restore;BeforeBuild"
Inputs="@(ProjectReference);$(MSBuildThisFileFullPath)"
Outputs="$(MSBuildProjectExtensionsPath)\$(MSBuildProjectName).csproj.proj.g.props;$(MSBuildProjectExtensionsPath)\$(MSBuildProjectName).csproj.proj.g.targets"
>
<CallTarget
Targets="CollectImportProjectReferenceProps"
Condition="'@(ProjectReference)' != ''"
>
<Output TaskParameter="TargetOutputs" ItemName="_ProjectProps"/>
</CallTarget>
<CallTarget
Targets="CollectImportProjectReferenceTargets"
Condition="'@(ProjectReference)' != ''"
>
<Output TaskParameter="TargetOutputs" ItemName="_ProjectTargets"/>
</CallTarget>
<!-- Collecting .props and .targets files for the ProjectReferences tree -->
<MSBuild
Projects="@(ProjectReference)"
Targets="CollectImportProjectReferenceProps"
Properties="_MSBuildProjectExtensionsPath=$(MSBuildProjectExtensionsPath);ImportOutput='false'"
Condition="'@(ProjectReference)' != ''"
>
<Output TaskParameter="TargetOutputs" ItemName="_ReferenceProps"/>
</MSBuild>
<MSBuild
Projects="@(ProjectReference)"
Targets="CollectImportProjectReferenceTargets"
Properties="_MSBuildProjectExtensionsPath=$(MSBuildProjectExtensionsPath)"
Condition="'@(ProjectReference)' != ''"
>
<Output TaskParameter="TargetOutputs" ItemName="_ReferenceTargets"/>
</MSBuild>
<ItemGroup>
<!-- Deduplicating items -->
<__Props Include="@(_ProjectProps);@(_ReferenceProps)" />
<__Targets Include="@(_ProjectTargets);@(_ReferenceTargets)" />
<_Props Include="@(__Props->Distinct())" />
<_Targets Include="@(__Targets->Distinct())" />
</ItemGroup>
<!-- Creating groups to hold the XML content for import statements -->
<ItemGroup Condition="@(_Props) != '' or @(_Targets) != ''">
<_Lines Include="<Project>" />
</ItemGroup>
<ItemGroup>
<!-- Include for .props files -->
<_PropsLines Include="<Project>" />
<_PropsLines Include="<Import Project='" Condition="@(_Props) != ''" />
<_PropsLines Include="@(_Props->'%(Identity);')" Condition="@(_Props) != ''" />
<_PropsLines Include="' />" Condition="@(_Props) != ''" />
<_PropsLines Include="</Project>" />
</ItemGroup>
<ItemGroup>
<!-- Include for .targets files -->
<_TargetsLines Include="<Project>" />
<_TargetsLines Include="<Import Project='" Condition="@(_Targets) != ''" />
<_TargetsLines Include="@(_Targets->'%(Identity);')" Condition="@(_Targets) != ''" />
<_TargetsLines Include="' />" Condition="@(_Targets) != ''" />
<_TargetsLines Include="</Project>" />
</ItemGroup>
<ItemGroup Condition="@(_Props) != '' or @(_Targets) != ''">
<_Lines Include="</Project>" />
</ItemGroup>
<PropertyGroup>
<_MSBuildProjectExtensionsPath Condition="'$(_MSBuildProjectExtensionsPath)' == ''">$(MSBuildProjectExtensionsPath)</_MSBuildProjectExtensionsPath>
</PropertyGroup>
<!-- Write the collected props and targets imports to a file -->
<WriteLinesToFile File="$(_MSBuildProjectExtensionsPath)\$(MSBuildProjectName).csproj.proj.g.props" Lines="@(_PropsLines)" Overwrite="true" />
<WriteLinesToFile File="$(_MSBuildProjectExtensionsPath)\$(MSBuildProjectName).csproj.proj.g.targets" Lines="@(_TargetsLines)" Overwrite="true" />
</Target>
<Target Name="CollectImportProjectReferenceProps" Outputs="@(_ProjectProps)">
<!-- Collecting .props and .targets files for the ProjectReferences -->
<ItemGroup>
<!-- Check for .props files in the build directory of the ProjectReferences -->
<_ProjectProps Include="@(ProjectReference->'%(RootDir)%(Directory)build\%(Filename).props')" Condition="Exists('%(RootDir)%(Directory)build\%(Filename).props')" />
</ItemGroup>
</Target>
<Target Name="CollectImportProjectReferenceTargets" Outputs="@(_ProjectTargets)">
<!-- Collecting .props and .targets files for the ProjectReferences -->
<ItemGroup>
<!-- Check for .targets files in the build directory of the ProjectReferences -->
<_ProjectTargets Include="@(ProjectReference->'%(RootDir)%(Directory)build\%(Filename).targets')" Condition="Exists('%(RootDir)%(Directory)build\%(Filename).targets')" />
</ItemGroup>
</Target>
<!--
Because most IDEs do not reload the project file up until after it has been modified, we need to force a reload of the project file by making a dummy change to it.
-->
<Target Name="ForceProjectReload" AfterTargets="ImportProjectReferenceBuildFiles">
<Touch Files="$(MSBuildProjectFullPath)">
<Output TaskParameter="TouchedFiles" ItemName="FilesTouched"/>
</Touch>
</Target>
</Project> |
I need to make project with some msbuild properties, tasks and targets which will be consumed by another project.
When my consumer-project references nuget package via
PackageReference
then consumer-projects can consume any assets: assemblies, content, props, targets and probably a lot more from package.But when my consumer-project references another project then consumer-project can consume only assembly.
Is it possible to consume other assets?
I've found next ProjectReference's metadata, but there is a little information in documentation. So, I don't know if this can help me.
Of course I can just manually write imports to my props and targets. But there must be a better way. Or not?
The text was updated successfully, but these errors were encountered: