Msbuild: Does not respect the location of BaseIntermediateOutputPath

Created on 6 May 2017  路  2Comments  路  Source: dotnet/msbuild

I am using dotnet core. When I changed the "obj" location using BaseIntermediateOutputPath, msbuild doesn't respect that path if there is already an obj in the subdirectory.

It doesn't work entirely. I am switching branches usually between old and new. Lets say our folder structure is as follows:

-Test\src\ -Test\src\test.csproj -Test\src\obj\
And the contents of my test.csproj is as follows:

  <PropertyGroup>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <AssemblyName>Test</AssemblyName>
    <OutputType>Exe</OutputType>
    <PackageId>Test</PackageId>
    <OutputPath>..\bin\</OutputPath>
    <BaseIntermediateOutputPath>..\obj</BaseIntermediateOutputPath>
    <PackageTargetFallback>$(PackageTargetFallback);dotnet5.6;portable-net45+win8</PackageTargetFallback>
  </PropertyGroup>

What msbuild would do is that iwill create a obj as a sibling to src.

-Test\src\ -Test\src\test.csproj -Test\src\obj\ -Test\obj\

The above is correct. It created the correct obj folder path. But when we build from console Visual Studio, known error pops up, but when I build using dotnet build, it fails:

\src\obj\project.assets.json' doesn't have a target for '.NETCoreApp,Version=v1.1'. Ensure you have restored this project for TargetFramework='netcoreapp1.1' and RuntimeIdentifier=''.

It shouldn't have used that obj location for the target framework.

Can msbuild respect the location of the obj folder in its csproj file?

Most helpful comment

Thanks for the feedback. Unfortunately there not a really great solution here because the root of the problem is you're setting the BaseIntermediateOutputPath too late. For various reasons, the .NET SDK had to defined that property in the "top" import (generally the .props file) that comes from the Sdk="Microsoft.NET.Sdk". An alternative would be to convert your project to explicitly importing the SDK. For example:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>
</Project>

Becomes:

<Project>
  <PropertyGroup>
    <BaseIntermediateOutputPath>..\obj</BaseIntermediateOutputPath>
  </PropertyGroup>
  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>
  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>

_Note the removal of the Sdk attribute on the Project element and the addition of the <Import> elements._

This will define BaseIntermediateOutputPath before the SDK is imported.

That being said, an even better solution is to define a Directory.Build.props file for your repo/solution. For example, placing a file with that name in the root of your enlistment with the following contents:

<Project>
  <PropertyGroup>
    <BaseIntermediateOutputPath>..\obj</BaseIntermediateOutputPath>
  </PropertyGroup>
</Project>

This will automatically be imported by MSBuild and define that property in all projects under that folder. You can also use Directory.Build.targets as well (imported at the end). This feature was added VS2017 to solve this sort of issue in a more global way (you don't have to do it in every project and don't have to modify new projects to import it). It was added in #751.

All 2 comments

Thanks for the feedback. Unfortunately there not a really great solution here because the root of the problem is you're setting the BaseIntermediateOutputPath too late. For various reasons, the .NET SDK had to defined that property in the "top" import (generally the .props file) that comes from the Sdk="Microsoft.NET.Sdk". An alternative would be to convert your project to explicitly importing the SDK. For example:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>
</Project>

Becomes:

<Project>
  <PropertyGroup>
    <BaseIntermediateOutputPath>..\obj</BaseIntermediateOutputPath>
  </PropertyGroup>
  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>
  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>

_Note the removal of the Sdk attribute on the Project element and the addition of the <Import> elements._

This will define BaseIntermediateOutputPath before the SDK is imported.

That being said, an even better solution is to define a Directory.Build.props file for your repo/solution. For example, placing a file with that name in the root of your enlistment with the following contents:

<Project>
  <PropertyGroup>
    <BaseIntermediateOutputPath>..\obj</BaseIntermediateOutputPath>
  </PropertyGroup>
</Project>

This will automatically be imported by MSBuild and define that property in all projects under that folder. You can also use Directory.Build.targets as well (imported at the end). This feature was added VS2017 to solve this sort of issue in a more global way (you don't have to do it in every project and don't have to modify new projects to import it). It was added in #751.

@AndyGerlicher , Hi, I have another question about it.
Is there any possible to separate some other files and some nuget files in obj folder ? like:

nuget.g.props
project.assets.json
.....

I always put my obj and bin file to temp folder(that will remove every time restart windows, but looks like the nuget files not a temporary files, So I want 2 path for temporary files and long-term files.
If I use Directory.Build.props set BaseIntermediateOutputPath path, the obj folder and all nuget files still remove together to the new path, that's really bothering me, I worry every time delete nuget files will cause some problems.
That would be very helpful if there is another path we could add in to it, like:

<Project>
  <PropertyGroup>
    <BaseIntermediateOutputPath>c:\windows\temp\project\</BaseIntermediateOutputPath>
   <NugetOutputPath>d:\nuget\</NugetOutputPath>
  </PropertyGroup>
</Project>

Is there any possible to do that? Thanks.

Was this page helpful?
0 / 5 - 0 ratings