Skip to content
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

Certain MSBuild configuration causes _wpftmp build output directories to not be deleted after each build #2930

Open
nathan-alden-hp opened this issue Apr 24, 2020 · 34 comments
Assignees
Labels
Investigate Requires further investigation by the WPF team. WindowsDesktop SDK

Comments

@nathan-alden-hp
Copy link

.NET Core 3.1.201
Windows 10 build 18363

Problem description:

Certain MSBuild configuration causes the compiler to leave behind directories with a _wpftmp suffix after a build completes. The problem seems to be related to custom <BaseOutputPath>s.

Actual behavior:

Temporary output directories are left behind after every build. A new directory is created per build.

Expected behavior:

Temporary output directories are deleted after every build.

Minimal repro:

WpfApp1.zip

image

@nathan-alden-hp nathan-alden-hp changed the title Certain MSBuild configuration causes _wpftmp build output directories to be left behind Certain MSBuild configuration causes _wpftmp build output directories to not be deleted after each build Apr 24, 2020
@jonesdwg
Copy link

jonesdwg commented Jul 3, 2020

Just confirming this is still an issue with 3.1.301. Only impacts WindowsDesktop sdk projects. In our case we have a custom <OutputPath>

@vatsan-madhavan
Copy link
Member

This is not a bug; By Design AFAICT.

Deleting build artifacts generated by the temp projects had never been a goal.

The only goal has been deleting the *wpftmp.csproj itself, because it is created alongside the original project inside the cone of the sources directory.

Depending on various build configuration choices, the output directories can be named after either (a) the target assembly or (b) the project name (or something else, which is uncommon).

When (a) is in effect, the *wpftmp.csproj project will simply happen to use the same folders under $(Obj) and $(Bin) as the original project - they happen to share the same target assembly name by design.

When (b) is in effect, msbuild will provision *wpftmp.csproj with its own folders under $(Obj) and $(Bin) based on the project name.

This works the same in .NET Framework and .NET Core; in SDK style projects and in older style projects.

@jonesdwg
Copy link

jonesdwg commented Jul 6, 2020

That's interesting, thanks. In our case however this does only seems to be impact WindowsDesktop sdk projects.

I've modified the solution provided by @nathan-alden-hp to include a wpf .net framework project and .net core console app: repro.zip

These all pick up their output path from the Directory.build.props, but it's only the sdk style WindowsDesktop project that leaves behind the temporary directories:

image

From what I understand I'm probably falling into scenario b as both the output path and intermediate path are modified based on the $(MSBuildProjectName)

<BaseArtifactsPath>$(MSBuildThisFileDirectory)artifacts\</BaseArtifactsPath><OutputPath>$(BaseArtifactsPath)bin\$(MSBuildProjectName)\</OutputPath> <BaseIntermediateOutputPath>$(BaseArtifactsPath)obj\$(MSBuildProjectName)\</BaseIntermediateOutputPath>

NB: I only see these extra directories left over in the bin directory, the obj directory is behaving as expected.

This does feel like a bug (or at least undesirable behaviour) and only started happening once we migrated our WPF apps to SDK style projects.

That said, I can work around it easily enough, by adding a post build step in Directory.build.targets to delete the directories:

<Target Name="RemoveWpfTemp" AfterTargets="Build"> <ItemGroup> <WpfTempDirectories Include="$([System.IO.Directory]::GetDirectories(&quot;$(BaseArtifactsPath)bin&quot;,&quot;$(MSBuildProjectName)_*_wpftmp&quot;))"/> </ItemGroup> <RemoveDir Directories="@(WpfTempDirectories)" /> </Target>

@nathan-alden-hp
Copy link
Author

I'm not sure why it should even be "by design" for a build system to repeatedly generate new directories that appear to never be cleaned or wiped...

@fabiant3 fabiant3 added this to the 5.0.0 milestone Jul 6, 2020
@msedi
Copy link

msedi commented Jul 16, 2020

Honestly, I also don't agree that temporary files and directories will not be deleted after the build has finished.
Also it is not deterministic when and why this happens. We changed some small detail in the project and we even don't know which option we have changed that it came to this behavior.

@dotMorten
Copy link
Contributor

dotMorten commented Jul 23, 2020

This behavior has been driving me nuts as well. This shouldn't be by-design. No other project type does this.

@msedi
Copy link

msedi commented Jan 30, 2021

Any news on this?

@ryalanms ryalanms added Bug Product bug (most likely) WindowsDesktop SDK Investigate Requires further investigation by the WPF team. and removed Bug Product bug (most likely) labels Feb 3, 2021
@chipplyman
Copy link

I confirm that this bug also affects non-SDK .NET Framework projects, as suggested by the last paragraph of vatsan-madhavan's comment from Jul 3, 2020.

I disagree with the assessment that it is not a bug. Even if the implementation is operating as designed, that merely shifts the root cause of the bug from the implementation to the design. This arguably makes it more a severe bug since it could have been caught earlier in the production pipeline and was not.

@nathan-alden-sr
Copy link

nathan-alden-sr commented Apr 29, 2021

I created this post-build target to deal with these folders:

<!--
  Delete temporary compiler output caused by this bug:
  https://github.com/dotnet/wpf/issues/2930
-->
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
  <Exec Command="FOR /D %%G in (&quot;$(BaseOutputBinPath)*_*_wpftmp&quot;) DO RMDIR /S /Q &quot;%%~G&quot;" />
</Target>

@ryalanms ryalanms modified the milestones: 5.0.0, 7.0.0 Aug 26, 2021
@msedi
Copy link

msedi commented Jan 13, 2022

Any news on this?

@HermanEldering
Copy link

HermanEldering commented Jan 14, 2022

I'm running into this issue as well. For those that want to investigate the issue themselves I believe this is where the problem originates and where the files but not directories are deleted: GenerateTemporaryTargetAssembly

The way I've worked around is by adding an extra <OutputPath> in my directory.build.props file, which has a condition like this:

<OutputPath Condition="$(MSBuildProjectName.EndsWith('_wpftmp'))">
    $(OutputBase)\Temp\tmpwpf\$(MSBuildProjectName)
</OutputPath>

Then there is a task to delete my entire tmpwpf folder so no artifacts are left behind.

Perhaps this is also a good solution for the WPF team? Just store the wpftmp projects somewhere else and delete that entire folder, instead of enumerating the files and deleting each one. It could be just a special subdirectory in the BaseIntermediateOutputPath or perhaps even a random directory in %temp%.

There are some other places in MSBuild that use the generated project name, so even if it is inside a new random directory the project name should perhaps remain like it is.

@ThomasGoulet73
Copy link
Contributor

ThomasGoulet73 commented Jan 14, 2022

OutputPath is never used, it uses IntermediateOutputPath to get the path of the assembly to build in GenerateTemporaryTargetAssembly. The folder created at OutputPath is created by PrepareForBuild but from what I can see, it's never used. This is the same bug as #5711. The problem is that it's evaluating properties with different values than the main build. We can't really evaluate every properties before the build in GenerateTemporaryTargetAssembly because it would break other projects that rely on the evaluation of properties inside GenerateTemporaryTargetAssembly . I have a potential fix that I'm experimenting with right now. It's working but I have to do more tests to make sure that I'm not breaking anything.

@msedi
Copy link

msedi commented Jan 14, 2022

And there is also an $(OutDir)... which we needed to set to $(OutputPath) to make our things work.

@HermanEldering
Copy link

@ThomasGoulet73 Those are good points you're making, I'll wait to see how your fix progresses.

@msedi
Copy link

msedi commented Feb 22, 2022

Any news on this?

@lindexi
Copy link
Member

lindexi commented Mar 3, 2022

@msedi It looks like VS2022 will try its best to clean out these folders...

@msedi
Copy link

msedi commented Mar 3, 2022

@lindexi: Thx. Do you know which version. I'm having the latest official version. Are you using the previews?

@msedi
Copy link

msedi commented Jun 10, 2022

Even with the latest Visual Studio preview the problem still exists (more than 2 years after....) 👎

@Wolf-K
Copy link

Wolf-K commented Jul 6, 2022

@lindexi: We are using VS 2022 17.2.5 and just noticed that our project folders are also polluted by random _wpftmp project files. Unfortunately all these files are also published to Github.

@msedi
Copy link

msedi commented Aug 26, 2022

Obviously the problem still isn't solved. Within 7 days my directory for one wpf library is polluted with 186 wpftmp folder. Is there any progress now?

image

@msedi
Copy link

msedi commented Feb 2, 2023

What is the status?

@chipplyman
Copy link

I successfully worked around this issue by replacing:
<OutputPath>some\path\including\$(MSBuildProjectName)\</OutputPath>
with
<OutputDirectory>$(MSBuildProjectName)</OutputDirectory>
<OutputDirectory Condition=" '$(AssemblyName)' != '' ">$(AssemblyName)</OutputDirectory>
<OutputPath>some\path\including\$(OutputDirectory)\</OutputPath>

Obviously this will not work for you if you need $(AssemblyName) to differ from $(MSBuildProjectName).

@msedi
Copy link

msedi commented May 22, 2023

@chipplyman: You are right, I need the $(AssemblyName) otherwise I would get too many write problems since with the multithreaded built to many files of the same name would be copied into the global target directory.

Vectron added a commit to Vectron/Vectron.Extensions.Hosting.Wpf that referenced this issue Jul 11, 2023
Vectron added a commit to Vectron/Vectron.Extensions.Logging.TextBlock that referenced this issue Jul 11, 2023
Vectron added a commit to Vectron/Vectron.Library.Wpf that referenced this issue Jul 11, 2023
@yamithrain
Copy link

Any news?

@lindexi
Copy link
Member

lindexi commented Aug 30, 2023

@yamithrain Could you test VisualStudio 2022 17.6.5 ?

@yamithrain
Copy link

The issue is still present with 17.6.6.

@lindexi
Copy link
Member

lindexi commented Aug 30, 2023

Sad...

@pchaurasia14 pchaurasia14 assigned Kuldeep-MS and unassigned ryalanms Aug 30, 2023
@msedi
Copy link

msedi commented Aug 30, 2023

I also still have this problem in the latest preview: 17.8.0 Preview 1.0

@pchaurasia14 pchaurasia14 assigned Kuldeep-MS and unassigned Kuldeep-MS Sep 7, 2023
@pchaurasia14 pchaurasia14 removed this from the 7.0.0 milestone Sep 7, 2023
@luttje
Copy link

luttje commented Oct 11, 2023

I also ran into this issue. I found the problem to be caused by:

<BaseOutputPath>..\..\bin\$(MSBuildProjectName)</BaseOutputPath>

In order to fix those *_wpftmp folders being created I've resorted to using this instead:

<BaseOutputPath>..\..\bin\$(AssemblyName)</BaseOutputPath>

I'm unaware of any side-effects with this configuration. Everything seems to work fine.

More (possibly relevant) information about my setup:

  • SDK-style project file
  • NET Framework 4.8
  • WPF UserControl
  • Output type:
    <OutputType>Library</OutputType>
  • References:
    <Reference Include="PresentationCore" />
    <Reference Include="PresentationFramework" />
    <Reference Include="System.Xaml" />
    <Reference Include="WindowsBase" />

Edit: Only after posting this did I notice someone above already mentioned this workaround:

I successfully worked around this issue by replacing:
<OutputPath>some\path\including\$(MSBuildProjectName)\</OutputPath>
with
<OutputDirectory>$(MSBuildProjectName)</OutputDirectory>
<OutputDirectory Condition=" '$(AssemblyName)' != '' ">$(AssemblyName)</OutputDirectory>
<OutputPath>some\path\including\$(OutputDirectory)\</OutputPath>

Obviously this will not work for you if you need $(AssemblyName) to differ from $(MSBuildProjectName).

luttje added a commit to luttje/Key2Joy that referenced this issue Oct 11, 2023
luttje added a commit to luttje/Key2Joy that referenced this issue Oct 14, 2023
* Start implementing plugins for better separation
* massive refactor in attempt to split appdomains for plugins
* (breaks old mapping profiles)
* Fix error when switching from mouse button trigger to keyboard trigger and clicking in the combobox where the mouse button capture textbox is.
* Simplify code by removing legacy
* SImplify grouping actions
* Fix profile and add helpful opposite mapping generator tool
* Change solution hierarchy
* Restrict AppDomain plugins went from Zone.MyComputer -> .Internet
* create keypair in ci
* Install the .NET framework tools
* Run command in workflow
* Plugin permissions. Plugins disabled by default
* update readme (icon is no longer used)
* Plugin action runs in seperated process
* Remove unused dependencies.
* Fix action name display for mapping
* Fix Lua plugin script calls (NOTE: laggy when using MessageBox)
* convert project to sdk style
* Add editorconfig and start cleaning up
* Fix documentation. Update namespaces to match files (breaks profiles)
* Include all projects in tests, disable building docs on debug
* Add messagebox script action
* Add tests for pluginhost
* Remove administrator from window title test
* add some icons to ui
* Add enabling/disabling plugins
* Close plugins when Key2Joy shuts down
* Fix appcommand failing
* Fix plugin permission form crashing. Fix plugin load exception not showing warning
* Handle plugin host closing better when app has crashed
* Seperate host and client logic in remote event subscriber
* Ensure the PluginHost shuts down if the app crashes
* Better error output for plugins
* Fix cmd interop not working, add some tests
* also generate docs on plugins
* Fix build order with docs
* Fix enum script parameters and ensure actions share environment scopes
* Fix _wpftmp folders being created dotnet/wpf#2930
* Fix sequence action. Add disabled trigger/action for unloaded plugins on startup
* Discover exposed Enums in plugins
* add doc link text + fix newline trimming + add tests
* add tests for whats easy to test (and generate tests for)
* have docs show returns; fix passing array to exposed method; incl tests
* remove assemblyinfo files (move to csproj)
* Add powershell build script
* add pre-release workflow
ronaldvanmanen added a commit to ronaldvanmanen/FFmpegSharp that referenced this issue Nov 18, 2023
ronaldvanmanen added a commit to ronaldvanmanen/FFmpegSharp that referenced this issue Nov 19, 2023
ronaldvanmanen added a commit to ronaldvanmanen/FFmpegSharp that referenced this issue Nov 20, 2023
@AFract
Copy link

AFract commented Jan 30, 2024

I am here due to the same problem (.Net 7.0, VS2022 17.8.5). I have thousands of those *wpftmp folders in my build folder...
I have a directory.build.props in my solution, I guess it is indirectly related.
Any structural update on it ?
Thank you

@lindexi
Copy link
Member

lindexi commented Jan 31, 2024

@AFract What is your code in Directory.Build.Props ?

@AFract
Copy link

AFract commented Feb 1, 2024

Hello, thank you for answering.
Here's the important part :

<Project>
	<PropertyGroup>
		<Version>1.0.0.0</Version>
		<AssemblyVersion>1.0.0.0</AssemblyVersion>
		<FileVersion>1.0.0.0</FileVersion>
		<IntermediateOutputPath>$(SolutionDir)Build\$(MSBuildProjectName)\obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>
		<OutputPath>$(SolutionDir)Build\$(MSBuildProjectName)\bin\$(Platform)\$(Configuration)\</OutputPath>
		<Platforms>x64</Platforms>
		<Configurations>Debug;Release</Configurations>
	</PropertyGroup>
	<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Any CPU'">
		<PlatformTarget>x64</PlatformTarget>
		<Optimize>true</Optimize>
		<DebugType>none</DebugType>
	</PropertyGroup>
	<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Any CPU'">
		<PlatformTarget>x64</PlatformTarget>
		<DebugSymbols>true</DebugSymbols>
		<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
	</PropertyGroup>
</Project>

@lindexi
Copy link
Member

lindexi commented Feb 4, 2024

@AFract Sorry, I can not repeat the problem with your Directory.Build.Props. And I think that there are other preconditions I don't know about.

Could you provisionally remove the <OutputPath> property in Directory.Build.Props to test? Maybe there can be fewer folders created.

@chibanemourad
Copy link

To resolve this bug, you have the choice between:

Redefine the property <AssemblyName> individually in each of your WPF csproj files as follows:

<AssemblyName>Your_Assembly_Name</AssemblyName>

Alternatively, in a more global way, Redefine the ProjectFriendlyName property in a Directory.Build.props file as follows:

<PropertyGroup Condition="$(ProjectFriendlyName.EndsWith('_wpftmp', StringComparison.CurrentCultureIgnoreCase))">
    <ProjectFriendlyName>$([System.IO.Path]::GetFileNameWithoutExtension($(ProjectFriendlyName)))</ProjectFriendlyName>
</PropertyGroup>

ronaldvanmanen added a commit to ronaldvanmanen/FFmpegSharp that referenced this issue Jun 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Investigate Requires further investigation by the WPF team. WindowsDesktop SDK
Projects
None yet
Development

No branches or pull requests