Open paulvanbrenk opened 6 years ago
Can you see if the documentation at https://docs.microsoft.com/en-us/visualstudio/msbuild/updating-an-existing-application helps? Feedback welcome, but I think it addresses your use case.
The documentation suggests it would, but I can't access the MSBuildLocator
type in my .NET Core app. (The assemblies in the package only target .NET 4.6).
When I run the project from the command line (using dotnet run
), I get some more information:
Unhandled Exception: Microsoft.Build.Exceptions.InvalidProjectFileException: The imported project "C:\vs\dogfood\MSBuild\15.0\Bin\15.0\Microsoft.Common.props" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk. C:\Program Files\dotnet\sdk\2.1.400-preview-008963\Sdks\Microsoft.NET.Sdk\Sdk\Sdk.props
at Microsoft.Build.Shared.ProjectErrorUtilities.ThrowInvalidProject(String errorSubCategoryResourceName, IElementLocation elementLocation, String resourceName, Object[] args) in /_/src/Shared/ProjectErrorUtilities.cs:line 412
at Microsoft.Build.Evaluation.Evaluator`4.ExpandAndLoadImportsFromUnescapedImportExpression(String directoryOfImportingFile, ProjectImportElement importElement, String unescapedExpression, Boolean throwOnFileNotExistsError, List`1& imports) in /_/src/Build/Evaluation/Evaluator.cs:line 2418
at Microsoft.Build.Evaluation.Evaluator`4.ExpandAndLoadImportsFromUnescapedImportExpressionConditioned(String directoryOfImportingFile, ProjectImportElement importElement, List`1& projects, Boolean throwOnFileNotExistsError) in /_/src/Build/Evaluation/Evaluator.cs:line 2173
at Microsoft.Build.Evaluation.Evaluator`4.ExpandAndLoadImports(String directoryOfImportingFile, ProjectImportElement importElement) in /_/src/Build/Evaluation/Evaluator.cs:line 1944
at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement) in /_/src/Build/Evaluation/Evaluator.cs:line 1823
at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) in /_/src/Build/Evaluation/Evaluator.cs:line 997
at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement) in /_/src/Build/Evaluation/Evaluator.cs:line 1825
at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) in /_/src/Build/Evaluation/Evaluator.cs:line 940
at Microsoft.Build.Evaluation.Evaluator`4.Evaluate(ILoggingService loggingService, BuildEventContext buildEventContext) in /_/src/Build/Evaluation/Evaluator.cs:line 726
at Microsoft.Build.Evaluation.Project.Reevaluate(ILoggingService loggingServiceForEvaluation, ProjectLoadSettings loadSettings) in /_/src/Build/Definition/Project.cs:line 2752
at Microsoft.Build.Evaluation.Project.ReevaluateIfNecessary(ILoggingService loggingServiceForEvaluation, ProjectLoadSettings loadSettings) in /_/src/Build/Definition/Project.cs:line 2719
at Microsoft.Build.Evaluation.Project.Initialize(IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext) in /_/src/Build/Definition/Project.cs:line 2822
at Microsoft.Build.Evaluation.Project..ctor(String projectFile, IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectCollection projectCollection, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext) in /_/src/Build/Definition/Project.cs:line 543
at Microsoft.Build.Evaluation.ProjectCollection.LoadProject(String fileName, IDictionary`2 globalProperties, String toolsVersion) in /_/src/Build/Definition/ProjectCollection.cs:line 1118
at ConsoleApp25.Program.DoWork() in d:\tmp\source\repos\ConsoleApp25\ConsoleApp25\Program.cs:line 44
at ConsoleApp25.Program.Main(String[] args) in d:\tmp\source\repos\ConsoleApp25\ConsoleApp25\Program.cs:line 37
The only Microsoft.Common.props
file I can find in my VS install directory is:
C:\vs\dogfood\MSBuild\15.0\Microsoft.Common.props
.
I can confirm that it doesn't work when Paul's app that uses MSBuild is targeting netcoreapp20:
Unhandled Exception: Microsoft.Build.Exceptions.InvalidProjectFileException: The imported project "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\15.0\Microsoft.Common.props" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk. C:\Program Files\dotnet\sdk\2.1.300-preview1-008174\Sdks\Microsoft.NET.Sdk\Sdk\Sdk.props
Looks like in both cases it's appending an unnecessary \15.0
to the path to Microsoft.Common.props.
Adding some SDK experts @dsplaisted @nguerrera. Still not sure if the bug is in the SDK or elsewhere, but hopefully someone can shed some light. The repro is easy (just had to change the hardcoded path to the test project on Paul's drive).
It is becoming more and more required, depending on the porting to the .net core. At the moment I don't see any libraries that provide the capabilities that this library provides, and there is no library that supports net core. Can anyone direct me to where the solution might be? I'm not yet familiar with the MSBuild code.
I just hit this issue. Are there any known workarounds?
MSBuildLocator now supports .NET Core applications. Are you using it, @Alxandr?
I'm using nuke-build
. So I'm not directly using anything. I might look into it though.
I tried doing the following:
using System;
using System.Collections.Generic;
using System.Text;
static class Program
{
public static int Main()
{
Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults();
return Build.Run();
}
}
And I still got the same error.
Here's output from the immediate window before doing Build.Run()
(I inserted >
in front of the input lines):
> Microsoft.Build.Locator.MSBuildLocator.IsRegistered
true
> Environment.GetEnvironmentVariable("MSBUILD_EXE_PATH")
"C:\\Program Files\\dotnet\\sdk\\2.2.300\\MSBuild.dll"
Edit: And it's failing here: https://github.com/nuke-build/common/blob/35404e91f1a283cddf5e5659ef7011ba44d17873/source/Nuke.Common/ProjectModel/ProjectModelTasks.cs#L47
Any news on this issue?
@Forgind @BenVillalobos
As far as I know MSBuildLocator should work on .NET Core. I'm not sure what the issue with nuke-build was, or whether it's been resolved yet.
It should, yes. @Alxandr, would you mind sharing the version of your repro that used MSBuildLocator?
I don't even remember which project I was using this on anymore, so I'm not going to to try to recreate it half a year later, sorry.
I can still easily reproduce the problem:
Use this .csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="16.8.0" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.8.0" />
</ItemGroup>
</Project>
and this .cs:
using Microsoft.Build.Evaluation;
class Program
{
private static void Main(string[] args)
{
var buildEngine = new ProjectCollection();
var project = buildEngine.LoadProject("some.csproj");
}
}
It works fine if you're targeting net472, but fails if you're targeting net5.0.
To workaround, you need to add a reference to Microsoft.Build.Locator. Change the .csproj to this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="16.8.0" ExcludeAssets="runtime" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.4.1" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.8.0" ExcludeAssets="runtime"/>
</ItemGroup>
</Project>
and the .cs to this:
using Microsoft.Build.Evaluation;
class Program
{
private static void Main(string[] args)
{
Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults();
Test();
}
private static void Test()
{
var buildEngine = new ProjectCollection();
var project = buildEngine.LoadProject("C:\\temp\\multi\\a\\a.csproj");
}
}
Note how the first usage of MSBuild API has to be in a separate method, because otherwise JIT will try to resolve Microsoft.Build.dll before MSBuildLocator was registered.
I'm still curious why the desktop version works without MSBuildLocator, but .NET 5 version needs it.
I'm still curious why the desktop version works without MSBuildLocator, but .NET 5 version needs it.
The part of this that confuses me is not that it doesn't work with .NET 5 but that it works with .NET Framework. It's meaningless to say you need __ part of the MSBuild API if you don't specify which version of MSBuild you want to use. That suggests to me that there's some default logic that tries to guess which MSBuild you are trying to use, in which case it would make sense that it would only be right if it knows what framework to use, and it presumably hasn't been updated since Core came out. I'm curious what would happen if you tried it on a computer with Core MSBuild but not Framework MSBuild.
For me everything works with .net 5.0, but as soon as I use .net 6.0 I have to use Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults();
any updates on this issue (at least for .net 6.0)?
What versions of MSBuild do you have? If you have net5.0 and net6.0 but nothing lower, that might validate my guess.
What versions of MSBuild do you have? If you have net5.0 and net6.0 but nothing lower, that might validate my guess.
I will check tomorrow, but I have VS 2019 and VS 2022 installed. .net core 3, .net 5 and .net 6.0 SDKs and runtimes.
I also have.net 4.7.2 installed. So I think I have the latest version of msbuild and at least one version before the latest version. Br
Ah, ok. Not what I'd been hoping, then. Thanks for checking.
I created a sample .NET Console app with the following code.
My project references the following 2 Nuget packages:
This gives the following exception when compiled to target .NET Core 2.0;
However it works as expected when targeting .NET 4.6.1
Any ideas?
ConsoleApp25.zip