I am using Visual Studio 15.8.5 and I have a multi-target project setup that sets the output path based on the target and build configuration (like output_dir\<Target>\<Configuration>). Since I want the target as the parent folder I need to set AppendTargetFrameworkToOutputPath to false. However this setting also causes the target framework part not to be appended to the obj folder resulting in CS2012 sometimes due to race condition.
Here is a sample project file to reproduce this issue:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net40;netstandard2.0</TargetFrameworks>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R_U_Debug|AnyCPU' ">
<OutputPath Condition=" '$(TargetFramework)' =='net40' ">..\..\Builds\net40\R_U_Debug\</OutputPath>
<OutputPath Condition=" '$(TargetFramework)' =='netstandard2.0' ">..\..\Builds\netstandard2.0\R_U_Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R_U_Release|AnyCPU' ">
<OutputPath Condition=" '$(TargetFramework)' =='net40' ">..\..\Builds\net40\R_U_Release\</OutputPath>
<OutputPath Condition=" '$(TargetFramework)' =='netstandard2.0' ">..\..\Builds\netstandard2.0\R_U_Release\</OutputPath>
</PropertyGroup>
</Project>
Here is the error I get sometimes when I try to build:
Error CS2012 Cannot open 'D:\Work\MyProject\obj\R_U_Debug\MyProject.dll' for writing -- 'The process cannot access the file 'D:\Work\MyProject\obj\R_U_Debug\MyProject.dll' because it is being used by another process.'
I tried setting a separate obj folder using the BaseIntermediateOuputPath property but this didn't take effect.
<BaseIntermediateOuputPath Condition=" '$(TargetFramework)' =='net40' ">obj\net40</BaseIntermediateOuputPath>
<BaseIntermediateOuputPath Condition=" '$(TargetFramework)' =='netstandard2.0' ">obj\netstandard2.0</BaseIntermediateOuputPath>
Perhaps the AppendTargetFrameworkToOutputPath property should not be apply to the intermediate obj folders.
I see this too using latest VS 15.9.11. Random file lock errors like above, unrequired rebuilds, and/or final dll for one of the target framworks missing at the end (has been deleted by the re-build).
I can't believe how much time I wasted on this before figuring out why my builds would randomly fail, and then how to fix it, and discovering how few people have run into the same thing
It seems the key issue here is that both the OutputPath and IntermediateOutputPath (for the bin and obj folders respectively) are not set when AppendTargetFrameworkToOutputPath is false
As such, in order to work around this you can simply define IntermediateOutputPath yourself in conjunction with disabling AppendTargetFrameworkToOutputPath. This will prevent IntermediateOutputPath from then being defined later on, allowing you to build multiple target frameworks at once, while specifying your own custom output directory (which likely still contains the $(TargetFramework), but at a different position within the folder path).
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)\$(Configuration)\$(TargetFramework.ToLowerInvariant())\</IntermediateOutputPath>
Note that at the point you would likely define this in your csproj, IntermediateOutputPath hasn't actually been defined yet; as such we have to manually spell out the default definition IntermediateOutputPath would use (obj\<configuration>) followed by the target framework that should be appended
Most helpful comment
I can't believe how much time I wasted on this before figuring out why my builds would randomly fail, and then how to fix it, and discovering how few people have run into the same thing
It seems the key issue here is that both the
OutputPathandIntermediateOutputPath(for the bin and obj folders respectively) are not set whenAppendTargetFrameworkToOutputPathisfalseAs such, in order to work around this you can simply define
IntermediateOutputPathyourself in conjunction with disablingAppendTargetFrameworkToOutputPath. This will preventIntermediateOutputPathfrom then being defined later on, allowing you to build multiple target frameworks at once, while specifying your own custom output directory (which likely still contains the$(TargetFramework), but at a different position within the folder path).Note that at the point you would likely define this in your csproj,
IntermediateOutputPathhasn't actually been defined yet; as such we have to manually spell out the default definitionIntermediateOutputPathwould use (obj\<configuration>) followed by the target framework that should be appended