-
Notifications
You must be signed in to change notification settings - Fork 392
Avoid duplicate 'WindowsAppRuntimeAutoInitializer.cpp' compilation #5895
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
base: main
Are you sure you want to change the base?
Conversation
LGTM |
@mschofie thanks for taking a stab at this. I don't think it's a complete fix, since we had to scrap a couple earlier attempts (#5685, #5782). My concern is that any batching at all (whether PreprocessorDefinitions, AdditionalOptions, etc) just sets a trap for subsequent dynamic source additions. Can we avoid batching entirely by applying macros to all sources after they've been dynamically added, and that supports Xaml generated sources, etc? |
Thanks for linking to the earlier attempts. TBH, both of those attempts appear to have the same problem as the original bug, that my approach doesn't. For example, #5782 says:
And that's not right - it's not that they're modifying the same
I don't understand how that mitigates the batching. If there's two <Project>
<ItemGroup>
<ClCompile Include="foo" PreprocessorDefinitions="FOO" />
<ClCompile Include="bar" PreprocessorDefinitions="BAR" />
</ItemGroup>
<Target Name="Build">
<Message Text="Batch: %(ClCompile.PreprocessorDefinitions) Items: %(ClCompile.Identity)" />
</Target>
</Project> If you're OK applying the preprocessor defines globally, then there's a much easier fix - simply decouple the ClCompile Item creation from setting the PreprocessorDefinitions metadata; i.e.
Property evaluation and ItemDefinitionGroup updates would have to happen outside of the 'Target', but I'm not sure that's a problem...? This is more 'order dependent' than this current PR, but we're in a .targets file, so I think it's OK. Thoughts? So, something like (I'm coding in an edit box; apologies for typos) <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WindowsAppRuntimeAutoInitializerPath>$(MSBuildThisFileDirectory)..\..\include\WindowsAppRuntimeAutoInitializer.cpp</WindowsAppRuntimeAutoInitializerPath>
<WindowsAppRuntimeAutoInitializerEnabled>false</WindowsAppRuntimeAutoInitializerEnabled>
<WindowsAppRuntimeAutoInitializerEnabled Condition="'$(WindowsAppSdkBootstrapInitialize)'=='true'">true</WindowsAppRuntimeAutoInitializerEnabled>
<WindowsAppRuntimeAutoInitializerEnabled Condition="'$(WindowsAppSdkDeploymentManagerInitialize)'=='true'">true</WindowsAppRuntimeAutoInitializerEnabled>
<WindowsAppRuntimeAutoInitializerEnabled Condition="'$(WindowsAppSdkUndockedRegFreeWinRTInitialize)'=='true'">true</WindowsAppRuntimeAutoInitializerEnabled>
<WindowsAppRuntimeAutoInitializerEnabled Condition="'$(WindowsAppSdkCompatibilityInitialize)'=='true'">true</WindowsAppRuntimeAutoInitializerEnabled>
</PropertyGroup>
<Target Name="WindowsAppRuntimeAutoInitializer" Condition=" '$(WindowsAppRuntimeAutoInitializerEnabled)'=='true' ">
<ItemGroup>
<ClCompile Include="$(WindowsAppRuntimeAutoInitializerPath)" />
</ItemGroup>
</Target>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions Condition="'$(WindowsAppSdkBootstrapInitialize)'=='true'">MICROSOFT_WINDOWSAPPSDK_AUTOINITIALIZE_BOOTSTRAP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(WindowsAppSdkDeploymentManagerInitialize)'=='true'">MICROSOFT_WINDOWSAPPSDK_AUTOINITIALIZE_DEPLOYMENTMANAGER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(WindowsAppSdkUndockedRegFreeWinRTInitialize)'=='true'">MICROSOFT_WINDOWSAPPSDK_AUTOINITIALIZE_UNDOCKEDREGFREEWINRT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(WindowsAppSdkCompatibilityInitialize)'=='true'">MICROSOFT_WINDOWSAPPSDK_AUTOINITIALIZE_COMPATIBILITY;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
</Project> |
Agreed - that's not a correct RCA
Right - I'm suggesting we eliminate batching via speciation of PreprocessorDefinitions (or any other %BatchingMetadata) and just apply metadata globally to all sources - pch, module, whatever. I had suggested doing that during execution after all sources were sure to have been ClCompile included. But I'm fine with doing it during evaluation phase, via ItemDefinitionGroup - that's very appealing. |
Sorry, I don't understand your suggestion. How would you add the PreprocessorDefines? You'd still need to utter At the minute, the only two paths I see are:
I'll update this PR with the |
Yes, you would - but that's not the issue per se. Having different definitions of PreprocessorDefines is what causes the batching. If we apply the same value to all sources, we get no batching and consequently no duplicate source compilation.
|
Indeed, and I don't think we can prevent different definitions of PreprocessorDefines, because customers can easily write valid vcxproj files with different definitions of PreprocessorDefines. A customer can write the following in their .vcxproj: <Project>
<ItemGroup>
<ClCompile Include="CustomerSource.cpp" />
<ClCompile Include="MoreCustomerSource.cpp" PreprocessorDefines="%(PreprocessorDefines);ENABLE_FANCY_MODE"/>
</ItemGroup>
</Project> And then batching will occur in an ItemGroup (in a Target) that uses |
That's true - we can't avoid that. But we can at least avoid self-inflicted issues like this one, by applying PreprocessorDefinitions globally. The interesting thing about this issue is that it's the result of our two targets both including ClCompile items with specific PreprocessorDefinitions: AddUndockedRegFreeWinRTCppDefines and WindowsAppRuntimeAutoInitializer. It's actually the second target that loses, by including its source file into separate batches that the first target has already created. So I'm fine with any solution that avoids our own (re)batching of existing batches. |
I've updated this PR with an implementation that takes the ItemDefinitionGroup-approach. This is - IMHO - a tidier approach. The only downside is that if customers are setting any of
within a 'Target', then it won't be honored, they need to be set during evaluation. This seems like a reasonable expectation to me. Thoughts? |
build/NuSpecs/WindowsAppSDK-Nuget-Native.AutoInitializer.targets
Outdated
Show resolved
Hide resolved
build/NuSpecs/WindowsAppSDK-Nuget-Native.AutoInitializer.targets
Outdated
Show resolved
Hide resolved
c5dd065
to
76c248a
Compare
I've addressed Christopher's comments - thanks! - and pushed a final version. TBH, I hadn't realized that the same pattern is used in multiple places across the build infrastructure - are folks with this PR going in without canonicalizing across the build? Where should I document - release notes? - the shift that the listed properties have to be set at evaluation time now?
|
We've already documented that these properties should be set in the project file (that language is imprecise, but implies outside a target): |
Fixes #5395.
build/NuSpecs/WindowsAppSDK-Nuget-Native.AutoInitializer.targets
attempts to add aClCompile
Item during theWindowsAppRuntimeAutoInitializer
Target. In doing so it attempts to use the existing metadata by uttering%(PreprocessorDefinitions)
. This syntax is fine forItemGroup
s outside of a Target, but within a Target, it causes the (implicit) task that creates the Item to be batched (documentation) - causing an Item with the Identity ofWindowsAppRuntimeAutoInitializer.cpp
to be added for every unique set ofClCompile.PreprocessorDefinitions
. The duplicateClCompile
Items cause a cascade of subsequent errors.The fix is to add the
ClCompile
in two steps:ClCompile
without specifying any metadata.'%(Identity)' == '$(WindowsAppRuntimeAutoInitializerPath)'
to force a single task batch (for the Item we're looking for).Thanks to @chwarr for help with this.