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

project.assets.json does not work with shared intermediates #4463

Open
davkean opened this issue Feb 1, 2017 · 43 comments
Open

project.assets.json does not work with shared intermediates #4463

davkean opened this issue Feb 1, 2017 · 43 comments
Labels
Functionality:Restore Priority:2 Issues for the current backlog. Type:DCR Design Change Request

Comments

@davkean
Copy link

davkean commented Feb 1, 2017

Files that generated into the intermediates, typically always include the project name in the name of the file:

Debug\ConsoleApp146.AssemblyInfo.cs
Debug\ConsoleApp146.csproj.FileListAbsolute.txt
Debug\ConsoleApp146.csprojResolveAssemblyReference.cache
Debug\ConsoleApp146.dll
Debug\ConsoleApp146.pdb
ConsoleApp146.1.0.0.nuspec
ConsoleApp146.csproj.nuget.g.props
ConsoleApp146.csproj.nuget.g.targets

The assets file does not:

project.assets.json

This is going to lead to clashes when projects share intermediate directories, which is pretty common in large projects such as Roslyn.

@rrelyea rrelyea added this to the 4.0.1 milestone Feb 1, 2017
@rrelyea
Copy link
Contributor

rrelyea commented Feb 1, 2017

good issue. we think we can change without too much work...but likely too late for rtm.
/cc @jainaashish @emgarten

@rrelyea rrelyea added Functionality:Restore Type:DCR Design Change Request labels Feb 1, 2017
@emgarten
Copy link
Member

emgarten commented Feb 1, 2017

Agreed, this would be a good change. We've been working towards making this file name/path extensible, but there a few places still expecting project.assets.json.

@davkean
Copy link
Author

davkean commented Feb 2, 2017

Yeah, let's fix it later - just make sure you coordinate with us.

@emgarten
Copy link
Member

emgarten commented Feb 2, 2017

$(ProjectAssetsFile) will contain the full path that NuGet writes to. This of course won't exist if the project hasn't been restored yet, so it might be hard to rely on this.

@davkean
Copy link
Author

davkean commented Feb 2, 2017

Good to know, we should be respecting that: dotnet/project-system#1437

@davkean
Copy link
Author

davkean commented Feb 10, 2017

Make note - this also affects two projects in the same directory: dotnet/project-system#1528

@caleblloyd
Copy link

When I define a different IntermediateOutputPath, nuget files still always end up in $(ProjectDir)\obj\. I am following this MSDN blog post

Example:

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <IntermediateOutputPath>$(SolutionDir)\obj\$(Configuration)\$(MSBuildProjectName)\</IntermediateOutputPath>
    <OutputPath>$(SolutionDir)\bin\$(Configuration)\$(AssemblyName)\</OutputPath>
  </PropertyGroup>

All other files get moved correctly, except for these 3 which still appear in $(ProjectDir)\obj\:

App.csproj.nuget.g.props
App.csproj.nuget.g.targets
project.assets.json

@emgarten
Copy link
Member

emgarten commented Feb 22, 2017

@caleblloyd NuGet reads BaseIntermediateOutputPath

update by @nkolev92

NuGet now respects MSBuildProjectExtensionsPath.

Please refer to dotnet/msbuild#1603 and NuGet/NuGet.Client#2131 and NuGet/NuGet.Client#2121.

Original comment: #4463 (comment)

@davkean
Copy link
Author

davkean commented Feb 23, 2017

Given where the base intermediate path is set, you can't set it without expanding SDK into explicit imports of a props and targets.

@caleblloyd
Copy link

caleblloyd commented Feb 23, 2017

I am trying to run a Docker container that has code mounted into it while also developing on the host inside of an IDE. The IDE keeps running Dotnet Restore and conflicting with the Docker container's Dotnet Restore.

I have to do multiple mounts to exclude the bin and obj folders if they are in the default path, so I thought maybe I'd move them using BaseIntermediateOutputPath. But this causes Entity Framework Tools and dotnet test to not work properly.

Is there another solution to this besides for waiting for the ability to name project.assets.json different names on the Host and in Docker? I can run different build configurations on the Host and Docker (e.g. run dotnet run -c Debug on the Host and run dotnet run -c Docker on Docker) and right now the only conflict I'm getting is that Nuget keeps clobbering the other side

@davkean
Copy link
Author

davkean commented Feb 23, 2017

Can you expand on the issues you have with EF and dotnet test when you change BaseIntermediateOutputPath with a bug over on http://github.com/roslyn-project-system? I'll move them to the appropriate repros if it's a bug in those tools.

@caleblloyd
Copy link

Yes, I will do that in a few days. Thanks!

@jdasilva
Copy link

@davkean Does this mean that having a shared intermediate folder is supported once these issues are fixed?

@davkean
Copy link
Author

davkean commented Mar 21, 2017

@jdasilva These are two issues that I found scouting it - but I've not confirmed that it's fully supported yet. Sounds like @caleblloyd was running into issues that I'd like to capture

@jdasilva
Copy link

Thanks, I was thinking about a comment like this dotnet/sdk#760 (comment). I've been using a common intermediate folder for a couple of projects since at least VS2013 and this still works under VS2017 with the old project system. I'd love to move to the new one, so I really meant "supported" in the sense of if something blocks this will it be considered a bug? You seem to be doing that already which is great and I just want to make sure I'm on the same page.

@davkean
Copy link
Author

davkean commented Mar 29, 2017

@jdasilva Sorry missed this comment (for some reason NuGet issues go to my personal email).

Yes we'd consider anything blocking multiple projects from building to a common intermediate as a bug - this is the reason that we prefix most things in obj with the project name. This issue is the last one that I know that is blocking building to a common intermediate folder (MSBuild fixed their last one)

@davkean
Copy link
Author

davkean commented Apr 6, 2017

Here's another issue that results as a problem of this - dotnet/project-system#1935. Basically, building a new csproj in the same directory as the old csproj, breaks the build because the old csproj picks up the same assets file.

@emgarten
Copy link
Member

emgarten commented Apr 7, 2017

@davkean when will dotnet/project-system#1437 be fixed?

@SwooshyCueb
Copy link

With this solution, could two project files exist in the same directory if they set MSBuildProjectExtensionsPath to different locations?

@jeffkl
Copy link
Contributor

jeffkl commented Oct 30, 2019

@SwooshyCueb yes that would work. As long as the MSBuildProjectExtensionsPath is unique, NuGet would be restore just fine. However, MSBuild will give you an error if you build in that directory and don't specify a project to build.

@nguerrera
Copy link

nguerrera commented Oct 30, 2019

I think a best effort should be made to make the path unique in common cases. Consider the trivial case of two projects in the same folder with default output paths. For ages, this simple case worked because everything put the project name in obj files, until assets file came along. So I think it is good to have the error as you suggest, but I still see value in being unique by default up to project name.

@zkat zkat removed the Priority:1 High priority issues that must be resolved in the current sprint. label Aug 31, 2020
@zkat zkat removed this from the Backlog milestone Aug 31, 2020
@zkat zkat added the Priority:2 Issues for the current backlog. label Aug 31, 2020
@nkolev92
Copy link
Member

There are no technical blockers anymore afaik.

The concern would be the migration plan.
For better or worse newer NuGet versions are often used with older build tooling, so this change would potentially break that.

This needs to be carefully analyzed to avoid fall outs similar to what we had to fix with dotnet/sdk#14517.

@mkonijnenburg
Copy link

mkonijnenburg commented Nov 10, 2021

This solution does not work anymore with net sdk 6.0 (installed yesterday)

Directory.build.props:

<BaseOutputPath>bin\$(MSBuildProjectName)\</BaseOutputPath>
<MSBuildProjectExtensionsPath>obj\$(MSBuildProjectName)\</MSBuildProjectExtensionsPath>
<IntermediateOutputPath>obj\$(MSBuildProjectName)\$(Configuration)\</IntermediateOutputPath>

C:\Program Files\dotnet\sdk\6.0.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(267,5): error NETSDK1004: Assets file 'D:\Applications\AAA\obj\BBB_yzakfkig_wpftmp\project.assets.json' not found. Run a NuGet package restore to generate this file. [D:\Applications\AAA\BBB_yzakfkig_wpftmp.csproj]

The error is only with WPF projects, the project.assests.json gets placed in the folder without the mangling (BBB).

@zivkan
Copy link
Member

zivkan commented Nov 10, 2021

@mkonijnenburg since this is specific to WPF, it's related to WPF's targets/props (SDK). I created an issue there: dotnet/wpf#5679

For what it's worth, the problem you found is unrelated to this issue. This isssue is about two csproj files in the same directory (or otherwise using the same obj folder). Your MSBuildProjectExtensionsPath contain the project name, hence every project has a different directory, they're not sharing the same directory, so there isn't a problem with two different projects trying to use the same project.assets.json file.

@mkonijnenburg
Copy link

mkonijnenburg commented Nov 10, 2021 via email

@Nirmal4G
Copy link

Nirmal4G commented Oct 7, 2022

I hit this so many times but there's no way to rename project.assets.json file with say, MSBuildProjectName to actually keep those files separate. I mean, the props/targets and dgspec files have project name to disambiguate.

From what I saw in both NuGet and .NET SDK targets, the work needs to be in both. I can think of two solutions here.

Most projects don't need disambiguation as they are restored in to their own project folder but cases like the above happen when the same project folder contains two projects (may be targeting different versions of the dependencies). This could be fixed with #5154 as you then no longer need two project workarounds.

Another requirement to have many projects within the same folder is to simply build different assemblies with varying public surface API (think, Lite and Full modules). With .NET Framework, we have netmodule, in essence, Both VB and C# code can present in the same folder and each project produces a netmodule and links them together to create a single assembly (this is one of the most underrated features of .NET, I don't know why the team removed it in Core.).

With those reasons stated above, I can think of two solutions here. One is to enable #5154 and other is to have a disambiguation between restore assets by project name or file when they are in the same folder. The former ask could be bigger than just a simple refactor but the latter could be just that depending on how the assets file feature is implemented in the codebase.

I'm willing to take this on If the team accepts the request and guides me on where I should make the changes.

@BryanAldrich
Copy link

I found this and whilst exploring the code and various properties, I found that adding a Directory.build.props file with the following content resolved the build issue where the project.assets.json conflicts with two projects.

  1. the project name the assets.json was built from should be in the file to detect multiple projects building into the same asset file. The rest of the output files seems to include the projectname, then file content, then extension. Seems that is reasonable.
  2. Nuget should respect the IntermediateOutputPath variable. It does only currently honor the RestoreOutputPath or MSBuildProjectExtensionsPath. The former being defaulted to the latter. With at least 3 variables used for the 'obj' folder, not all of them being used equivalently either.

Just ideas and notes I had whilst resolving my current issue.

<Project>
  <!-- See https://aka.ms/dotnet/msbuild/customize for more details on customizing your build -->
  <PropertyGroup>
    <BaseIntermediateOutputPath>obj\$(Configuration)\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
  </PropertyGroup>
</Project>

yes, i realize that i end up with $(Configuration) in my folder twice, but this lets me build debug and release versions of our internal nuget packages and swap them out on the fly. If IntermediateOutputPath was respected by nuget, then i could remove one layer, it's inconsequential as long it builds, deploys and runs.

@BryanAldrich
Copy link

To reply to my prior comment, it gets worse. The Azure DevOps task for Nuget Restore generates a new targets file for msbuild, then calls it. Thus, completely obliterating any chance of finding the Directory.Build.props file.

@nkolev92
Copy link
Member

@BrightLight

You're hitting a limitation in NuGet.exe, tracked in #6734.

If possible, we recommend using msbuild /t:restore instead of the Nuget restore task. It even supports packages.config. https://learn.microsoft.com/en-us/nuget/reference/msbuild-targets#restoring-packagereference-and-packagesconfig-projects-with-msbuild.

Regarding the IntermediateOutputPath idea, NuGet is explicitly configuration agnostic, but that itself really related to this particular issue.
MSBuildProjectExtensionsPath was added explicitly for NuGet, so if you want 2 projects in the same folder to not share the same intermediates, just make that's set to different paths for different projects.

@BryanAldrich
Copy link

@nkolev92 Thanks, I actually switched to the msbuild command yesterday, i'm glad though to see that it is a recommended path. Thanks for the advise and everything you do!

@Cygon
Copy link

Cygon commented Jul 24, 2024

I'm running into this with nearly any project I have, since I like to have my unit tests close to the code, i.e.

Nuclex.Support/
    Source/
        UsefulThing.cs

    Tests/
        UsefulThingTest.cs

    Nuclex.Support.csproj
    Nuclex.Support.Tests.csproj

Those .csproj files would be two .NET Standard 2.0 projects. I can set different intermediate directories (i.e. obj/source/... and obj/tests/...) and both assemblies will compile without issue.

Except when I introduce NuGet, i.e. to add NUnit or Moq as dependencies: the unit test project will fail to compile as if NUnit or Moq weren't present in the dependencies. There is no build message of any kind to indicate that the NUnit reference was invalid or dropped or anything - so it likely uses the dependencies of the non-unit-test project.

Since this project.assets.json is a mere intermediate file, couldn't it just be given a unique name or put in the user-defined intermediate directory?

@nkolev92
Copy link
Member

You can use MSBuildProjectExtensionsPath to define a unique location for the assets file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Functionality:Restore Priority:2 Issues for the current backlog. Type:DCR Design Change Request
Projects
None yet
Development

No branches or pull requests