dotnet / msbuild

The Microsoft Build Engine (MSBuild) is the build platform for .NET and Visual Studio.
https://docs.microsoft.com/visualstudio/msbuild/msbuild
MIT License
5.23k stars 1.35k forks source link

MSBuild.exe is still running after a build in visual Studio 15.7.2 #3342

Closed djonasdev closed 5 years ago

djonasdev commented 6 years ago

Steps to reproduce

Project file

<?xml version="1.0" encoding="utf-8"?>
<Project TreatAsLocalProperty="NodeReuse" ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <MSBUILDDISABLENODEREUSE>True</MSBUILDDISABLENODEREUSE>
    <NodeReuse>False</NodeReuse>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <ProductVersion>3.10</ProductVersion>
    <ProjectGuid>6468764d-0126-47a0-b4f6-8fd64a9a6023</ProjectGuid>
    <SchemaVersion>2.0</SchemaVersion>
    <OutputName>VorlageSetup</OutputName>
    <OutputType>Package</OutputType>
    <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
    <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
    <RunPostBuildEvent>Always</RunPostBuildEvent>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
    <OutputPath>bin\$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
    <DefineConstants>Debug;</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <OutputPath>bin\$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Product.wxs" />
  </ItemGroup>
  <ItemGroup>
    <WixExtension Include="WixUtilExtension">
      <HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
      <Name>WixUtilExtension</Name>
    </WixExtension>
    <WixExtension Include="WixNetFxExtension">
      <HintPath>$(WixExtDir)\WixNetFxExtension.dll</HintPath>
      <Name>WixNetFxExtension</Name>
    </WixExtension>
  </ItemGroup>
  <ItemGroup>
    <Content Include="HtPlcFrameworkGui.ico" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\MyProject\MyProject.csproj">
      <Name>MyProject</Name>
      <Project>{4b29025d-9d0e-4fea-b204-25687cef94b2}</Project>
      <Private>True</Private>
      <DoNotHarvest>True</DoNotHarvest>
      <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
      <RefTargetDir>INSTALLFOLDER</RefTargetDir>
    </ProjectReference>
  </ItemGroup>
  <Import Project="$(WixTargetsPath)" />
  <PropertyGroup>  
  </PropertyGroup>
  <PropertyGroup>
    <LibrariesDir>$(IntermediateOutputPath)\libraries\</LibrariesDir>
    <DefineConstants>LibraryFiles=$(IntermediateOutputPath)\libraries</DefineConstants>
  </PropertyGroup>
  <PropertyGroup>
    <PostBuildEvent />
  </PropertyGroup>
  <PropertyGroup>
    <PreBuildEvent />
  </PropertyGroup>
  <!--
    To modify your build process, add your task inside one of the targets below and uncomment it.
    Other similar extension points exist, see Wix.targets.
    -->
  <Target Name="BeforeBuild">
    <Message Text="Deleting old installer files..." Importance="high" />
    <CreateItem Include="$(TargetDir)*.msi">
      <Output TaskParameter="Include" ItemName="MsiFiles" />
    </CreateItem>
    <Delete Files="@(MsiFiles)" />
    <Message Text="Gathering libraries..." Importance="high" />
    <CreateItem Include="..\MyProject\bin\$(Configuration)\*.dll">
      <Output TaskParameter="Include" ItemName="LibraryFiles" />
    </CreateItem>
    <CreateItem Include="..\MyProject\bin\$(Configuration)\Config\*.*">
      <Output TaskParameter="Include" ItemName="ConfigFiles" />
    </CreateItem>
    <CreateItem Include="..\MyProject\bin\$(Configuration)\x64\*.dll">
      <Output TaskParameter="Include" ItemName="LibraryX64Files" />
    </CreateItem>
    <CreateItem Include="..\MyProject\bin\$(Configuration)\x86\*.dll">
      <Output TaskParameter="Include" ItemName="LibraryX86Files" />
    </CreateItem>
    <MakeDir Directories="$(LibrariesDir)" />
    <MakeDir Directories="$(LibrariesDir)Config" />
    <MakeDir Directories="$(LibrariesDir)x64" />
    <MakeDir Directories="$(LibrariesDir)x86" />
    <Copy SourceFiles="@(LibraryFiles)"    DestinationFolder="$(LibrariesDir)" />
    <Copy SourceFiles="@(ConfigFiles)"     DestinationFolder="$(LibrariesDir)Config" />
    <Copy SourceFiles="@(LibraryX64Files)" DestinationFolder="$(LibrariesDir)x64" />
    <Copy SourceFiles="@(LibraryX86Files)" DestinationFolder="$(LibrariesDir)x86" />
    <Message Text="Heating libraries..." Importance="high" />
    <HeatDirectory DirectoryRefId="INSTALLLOCATION" OutputFile="$(IntermediateOutputPath)\Library.wxs" Directory="$(LibrariesDir)" ComponentGroupName="LibraryFiles" ToolPath="$(WixToolPath)" PreprocessorVariable="var.LibraryFiles" AutogenerateGuids="true" SuppressRootDirectory="true" />
    <ItemGroup>
      <Compile Include="$(IntermediateOutputPath)\Library.wxs" />
    </ItemGroup>
  </Target>
  <Target Name="AfterBuild">
    <Exec Command="gitsemver filename -f $(TargetPath)" />
  </Target>
</Project>

Command line

msbuild /nodeReuse:false /p:Configuration=Installer

Expected behavior

MSBuild should close after build

Actual behavior

MSBuild is still running building from VisualStudio. If running from command line, everything works as expected!

Environment data

msbuild /version output: 15.7.179.6572

OS info:

rainersigwald commented 6 years ago

Setting MSBUILDDISABLENODEREUSE inside a project doesn't have any effect--it must be set as an environment variable before the entry-point project starts executing. To affect Visual Studio, that means it must be set in the environment before launching devenv.exe.

Note that since Visual Studio has started doing more builds out-of-process (as a robustness and responsiveness improvement), this could significantly hurt your VS experience.

Why are you trying to set this?

djonasdev commented 6 years ago

Hey @rainersigwald, I have noticed that setting it in a project doesn't take effect (how embarrassing)!

Unfortunately setting it in the project file does also not take the effect. The MSBuild.exe is still running afterwards.

Why are you trying to set this?

I pre-build the complete "install structure" in the "obj" folder.

<Target Name="BeforeBuild">
    <Message Text="Deleting old installer files..." Importance="high" />
    <CreateItem Include="$(TargetDir)*.msi">
      <Output TaskParameter="Include" ItemName="MsiFiles" />
    </CreateItem>
    <Delete Files="@(MsiFiles)" />
    <Message Text="Gathering libraries..." Importance="high" />
    <CreateItem Include="..\MyProject\bin\$(Configuration)\*.dll">
      <Output TaskParameter="Include" ItemName="LibraryFiles" />
    </CreateItem>
    <CreateItem Include="..\MyProject\bin\$(Configuration)\Config\*.*">
      <Output TaskParameter="Include" ItemName="ConfigFiles" />
    </CreateItem>
    <CreateItem Include="..\MyProject\bin\$(Configuration)\x64\*.dll">
      <Output TaskParameter="Include" ItemName="LibraryX64Files" />
    </CreateItem>
    <CreateItem Include="..\MyProject\bin\$(Configuration)\x86\*.dll">
      <Output TaskParameter="Include" ItemName="LibraryX86Files" />
    </CreateItem>
    <MakeDir Directories="$(LibrariesDir)" />
    <MakeDir Directories="$(LibrariesDir)Config" />
    <MakeDir Directories="$(LibrariesDir)x64" />
    <MakeDir Directories="$(LibrariesDir)x86" />
    <Copy SourceFiles="@(LibraryFiles)"    DestinationFolder="$(LibrariesDir)" />
    <Copy SourceFiles="@(ConfigFiles)"     DestinationFolder="$(LibrariesDir)Config" />
    <Copy SourceFiles="@(LibraryX64Files)" DestinationFolder="$(LibrariesDir)x64" />
    <Copy SourceFiles="@(LibraryX86Files)" DestinationFolder="$(LibrariesDir)x86" />
    <Message Text="Heating libraries..." Importance="high" />
    <HeatDirectory DirectoryRefId="INSTALLLOCATION" OutputFile="$(IntermediateOutputPath)\Library.wxs" Directory="$(LibrariesDir)" ComponentGroupName="LibraryFiles" ToolPath="$(WixToolPath)" PreprocessorVariable="var.LibraryFiles" AutogenerateGuids="true" SuppressRootDirectory="true" />
    <ItemGroup>
      <Compile Include="$(IntermediateOutputPath)\Library.wxs" />
    </ItemGroup>
  </Target>

When I try to setup/customize the setup and build/rebuild the setup.msi several times, all files in the "obj" folder are still locked. When changing some parameters, the "old" files/folder structures are still kept and the setup.msi file is producing the wrong output on installing.


My current solution is building the solution from console (there is it working as expected! The MSBuild.exe is closed afterwards)

My workmate does not have this problem using the same solution. So maybe there is something wrong with my VisualStudio installation.

Adam-S-Daniel commented 6 years ago

I have had the same problem in Visual Studio 2017. I work around it by adding Condition="$(DesignTimeBuild) != true And $(BuildingProject) == true" to my custom targets. See: Determining whether a target is run in a design-time build

djonasdev commented 6 years ago

@geeeyetee thanks for reply.

What should I do then, if I know it is build by VS?

Adam-S-Daniel commented 6 years ago

Not sure I understand your question, but maybe this will help clarify: The condition evaluates to true when you initiate a build in Visual Studio, but to false during the design-time builds that Visual Studio performs in the background. In my project, this has prevented the locking of files in obj\ by persistent instances of MSBuild.exe.

delfuria commented 5 years ago

Hi, any news about this issue ? It's very annoying and It's still present in 15.9.13 version !!! Thanks

Jmales commented 5 years ago

I'm having this issue as well, but only with the new CSProj format <Project Sdk="Microsoft.NET.Sdk"> In my case I have a target which generates some .cs files. And because of this issue, while VS is opened, the files are infinitely being generated and deleted.

@geeeyetee 's workaround solved my problem though ;)

rainersigwald commented 5 years ago

Closing this as I think everything is by design:

  1. Node reuse can't be configured within a project.
  2. Design time builds are expected to run often in Visual Studio--see more information I posted on a linked issue: https://github.com/dotnet/sdk/issues/3627#issuecomment-530047390

As always, we can reopen if necessary.

Uxorious commented 3 years ago

Man I wish this would get fixed. It's SO annoying that I can't clean a build directory after closing VS.

danmoseley commented 3 years ago

@rainersigwald can they not set the environment variable to disable node reuse?

rainersigwald commented 3 years ago

@Uxorious

It's SO annoying that I can't clean a build directory after closing VS.

Closing VS should close all MSBuild.exe worker nodes; if you're not seeing that please open a Visual Studio feedback ticket and include a trace of the repro.

In addition, MSBuild shouldn't hold a lock on anything in the build output folder. Can you please file a new issue with details about what you're seeing held open?

rainersigwald commented 3 years ago

can they not set the environment variable to disable node reuse?

Yes, MSBUILDDISABLENODEREUSE=1 will prevent long-lived MSBuild.exe processes (at the cost of performance, since we can't preserve caches/avoid process-startup and JIT costs).

Uxorious commented 3 years ago

Hmm all I do is: mkdir build pushd build cmake -G "Visual Studio 16 2019" .. popd

Launch VS and build the project. Close VS after it's built.

rmdir /S /Q build

Then that will tell me it can't delete the directory (though all files within are gone).

I guess I'll investigate what exactly is holding on to the directory.

rainersigwald commented 3 years ago

Yes, please, that should work twice over (we shouldn't lock anything and even if we did we should close our processes when VS closes). Process Explorer has a handle-search feature that should help figure out the process + file that's holding the lock.

Uxorious commented 3 years ago

Interesting. If I do what I described above, it works. But if I do: Start explorer, and navigate to "build" directory. Double-click on the solution. ALT-TAB back to explorer and close it. Back in VS, build. Close VS.

Now if I try removing the build directory, it gives me the error. And ProcessExplorer says:

SOMEPID PATH_TO_BUILD