-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Option to run target once per project in multi-targeting build #2781
Comments
A sample application would be very helpful, as would reviewing the issue title and other aspects of your write-up for conformance with the Creating New Issues guidance at https://github.com/Microsoft/msbuild/wiki/Contributing-Code. |
Looks like I was able to find a solution - but it looks over-complicated, so let me leave this issue open. <ItemGroup>
<None Include="Sample.xsd" />
<Compile Remove="Sample.cs" /> <!--If it was included already, remove it to avoid duplicate -->
<Compile Include="Sample.cs" /> <!--Include it always, even if files don't exist -->
<DependentUpon>Sample.xsd</DependentUpon>
</Compile>
</ItemGroup>
<!--It could be optional BeforeTargets="CompileDesignTime;BeforeBuild", to allow VS generate it on first project openning-->
<Target Name="GenerateXsd" BeforeTargets="BeforeBuild" Inputs="Sample.xsd" Outputs="Sample.cs">
<PropertyGroup>
<GenerateXsd_Command>"$(SDK40ToolsPath)xsd.exe" "Sample.xsd" /nologo /c </GenerateXsd_Command>
</PropertyGroup>
<Exec Command="$(GenerateXsd_Command)" ConsoleToMSBuild="true" />
</Target> It works great, until we enable multi-targeting with something like: <TargetFrameworks>net40;netstandard2.0</TargetFrameworks> Now BeforeTargets will be executed twice - for net40 build and netstandard2.0 build. It is problem, as now we have race condition when two xsd tries to generate same file and one of it could not access it, because other locks it. My naive attempt to solve it was changing it to Final working solution looks next: <!--It could be optional BeforeTargets="CompileDesignTime", to allow VS generate it on first project openning-->
<Target Name="GenerateXsdInner" Inputs="Sample.xsd" Outputs="Sample.cs">
<PropertyGroup>
<GenerateXsd_Command>"$(SDK40ToolsPath)xsd.exe" "Sample.xsd" /nologo /c</GenerateXsd_Command>
</PropertyGroup>
<Exec Command="$(GenerateXsd_Command)" ConsoleToMSBuild="true" />
</Target>
<Target Name="GenerateXsd" BeforeTargets="DispatchToInnerBuilds;BeforeBuild">
<!--TargetFramework=once is critical here, as it allow will not execute task from same project with same properties twice.
We need to unify TargetFramework between empty, net40 and netstandard2.0-->
<MSBuild Projects="$(MSBuildProjectFile)" Targets="GenerateXsdInner" Properties="TargetFramework=once" />
</Target> I'm interested, if I missed some way to make it simpler? |
I was totally wrong. There is no consistent way to hook up into the outer build. Another option, if the code generator is trivially quick and you treat the source as transient, output the file to the |
How the pakcage nuget tagert? |
|
This will avoid running the target altogether on the other frameworks, which can have side effects like an inner build for a framework racing ahead of the other framework generating the file and failing at a later target because the files don't exist yet. What is really needed here is a target property that indicates that all inner builds should serialize on that target. |
…eAssemblyReferences (see also dotnet/msbuild#2781). Since cswinrt.exe is moving to forked code gen based on TFM, will just adopt that now, and resolve build breaks.
…eAssemblyReferences (see also dotnet/msbuild#2781). Since cswinrt.exe is moving to forked code gen based on TFM, will just adopt that now, and resolve build breaks. (#315)
I tried the work around given by @iskiselev, but it doesn't work when the targets are inside a NuGet or any NuGet contributes This can be fixed by specifying an existing <PropertyGroup>
<FirstTargetFramework Condition=" '$(TargetFrameworks)' == '' ">$(TargetFramework)</FirstTargetFramework>
<FirstTargetFramework Condition=" '$(FirstTargetFrameworks)' == '' ">$(TargetFrameworks.Split(';')[0])</FirstTargetFramework>
</PropertyGroup>
<MSBuild Projects="$(MSBuildProjectFile)" Targets="GenerateXsdInner" Properties="TargetFramework=$(FirstTargetFramework)" /> I also vote for providing a mechanism which is easier to use. |
…eAssemblyReferences (see also dotnet/msbuild#2781). Since cswinrt.exe is moving to forked code gen based on TFM, will just adopt that now, and resolve build breaks. (#315)
I'm trying to generate some additional sources for multi-targeting project (with TargetFrameworks).
Sources will be the same for both TargetFramework. When I attach my target with BeforeTargets to BeforeBuild, it will be executed twice - and with /m switch it may fail as both will try to generate same file.
I've tried to solve it by moving it to BeforeTargets DispatchToInnerBuilds and target really executed only once at correct time with 1-project solution. When solution contains more than one project and they reference, build could be started from ResolveReference target of other project. In that way it will be run in parallel with my source-generating target, which is not what I want.
Is there any way to run target only once in multi-targeting project and still be sure, that all compile-related task will be executed only after it?
I could provide sample application if it help.
The text was updated successfully, but these errors were encountered: