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

Multi-targeting: Error CS2012 sometimes when AppendTargetFrameworkToOutputPath is set to false #3787

Open
sansjunk opened this issue Sep 25, 2018 · 2 comments
Labels

Comments

@sansjunk
Copy link

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.

Steps to reproduce

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>

Actual behavior

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.'

Expected behavior

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.

@Gav-Brown
Copy link

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).

@lordmilko
Copy link

lordmilko commented Jul 5, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants