microsoft / MSBuildLocator

An API to locate MSBuild assemblies from an installed Visual Studio location. Use this to ensure that calling the MSBuild API will use the same toolset that a build from Visual Studio or msbuild.exe would.
Other
218 stars 83 forks source link

RegisterDefaults should not return a Visual Studio instance without MSBuild #73

Closed gremlm closed 4 years ago

gremlm commented 5 years ago

For calculating code metrics I have included Microsoft.CodeAnalysis.Metrics 2.9.4 nuget package to my csproj project. Before executing msbuild from the command line, I have called "nuget.exe restore", and it correctly found MSBuild and restore package:

"MSBuild auto-detection: using msbuild version '16.200.19.32702' from 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\bin'. Restoring NuGet package Microsoft.CodeAnalysis.Metrics.2.9.4. ..."

Then, from command line I am calling msbuild with /t:Metrics option:

"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\bin\MSBuild.exe" /p:Configuration=Debug /t:Metrics My.sln "

which ended with following error:

"Unhandled Exception: System.ArgumentException: Directory "C:\Program Files (x86)\Microsoft Visual Studio\2019\TestAgent\MSBuild\Current\Bin" does not exist Parameter name: msbuildPath at Microsoft.Build.Locator.MSBuildLocator.RegisterMSBuildPath(String msbuildPath) at Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults() at Metrics.Program.d__1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)"

It looks like Metrics.exe looking for msbuild in wrong location, but nugget.exe in correct one?

rainersigwald commented 5 years ago

NuGet.exe does use different logic for locating MSBuild. In this case, it looks like the machine has the TestAgent SKU of Visual Studio installed, which doesn't include MSBuild. That is the first Visual Studio installation that the Setup API returns to us and thus gets used in RegisterDefaults().

Locator should filter out results that don't have MSBuild installed. I'm going to update this bug description for that.

For now, you can change your code to be robust against this situation by checking for MSBuild.exe relative to the VisualStudioInstance.VisualStudioRootPaths returned from QueryVisualStudioInstances.

gremlm commented 5 years ago

By the way, I have installed both Visual Studio Professional 2019 and Visual Studio Build tools. In this case MSBuild is installed twice in different locations on the same system!

Both locations of MSBuild are not referenced by PATH environment variable after installation.

Both locations are not found by MSBuildLocator! Instead it was looking in absolutely different directory!!!

gremlm commented 5 years ago

For now, you can change your code to be robust against this situation by checking for MSBuild.exe relative to the VisualStudioInstance.VisualStudioRootPaths returned from QueryVisualStudioInstances.

I can do this during execution of MSBuild from command line? How ?

rainersigwald commented 5 years ago

In this case MSBuild is installed twice in different locations on the same system! ... Both locations of MSBuild are not referenced by PATH environment variable after installation.

That's expected, and is why MSBuildLocator exists: to find MSBuild installations and offer options for client applications to select among them.

Instead it was looking in absolutely different directory!!!

Can you please report the results of running

"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -all -prerelease

? I suspect you have more than just the two Visual Studio instances you mentioned installed.

I can do this during execution of MSBuild from command line? How ?

No, you cannot. I thought from your original description that you controlled the source code of the tool that called MSBuildLocator. Since it is third-party code, you can't control it directly.

However, there may be a good workaround for you. How are you running your build? Can you run it inside a Developer Command Prompt for VS 2019 environment? Does it behave the same way there?

gremlm commented 5 years ago
  1. Results of the execution "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -all -prerelease

Visual Studio Locator version 2.6.7+91f4c1d09e [query version 2.1.1046.44959] Copyright (C) Microsoft Corporation. All rights reserved.

instanceId: 9591a3ee installDate: 4/26/2019 5:22:40 PM installationName: VisualStudio/16.2.0+29123.88 installationPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional installationVersion: 16.2.29123.88 productId: Microsoft.VisualStudio.Product.Professional productPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\devenv.exe state: 4294967295 isComplete: 1 isLaunchable: 1 isPrerelease: 0 isRebootRequired: 0 displayName: Visual Studio Professional 2019 description: Professional developer tools and services for small teams channelId: VisualStudio.16.Release channelUri: https://aka.ms/vs/16/release/channel enginePath: C:\Program Files (x86)\Microsoft Visual Studio\Installer\resources\app\ServiceHub\Services\Microsoft.VisualStudio.Setup.Service releaseNotes: https://go.microsoft.com/fwlink/?LinkId=660893#16.2.0 thirdPartyNotices: https://go.microsoft.com/fwlink/?LinkId=660909 updateDate: 2019-08-06T01:36:05.3200805Z catalog_buildBranch: d16.2 catalog_buildVersion: 16.2.29123.88 catalog_id: VisualStudio/16.2.0+29123.88 catalog_localBuild: build-lab catalog_manifestName: VisualStudio catalog_manifestType: installer catalog_productDisplayVersion: 16.2.0 catalog_productLine: Dev16 catalog_productLineVersion: 2019 catalog_productMilestone: RTW catalog_productMilestoneIsPreRelease: False catalog_productName: Visual Studio catalog_productPatchVersion: 0 catalog_productPreReleaseMilestoneSuffix: 5.0 catalog_productSemanticVersion: 16.2.0+29123.88 catalog_requiredEngineVersion: 2.2.3062.31357 properties_campaignId: properties_channelManifestId: VisualStudio.16.Release/16.2.0+29123.88 properties_nickname: properties_setupEngineFilePath: C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installershell.exe

  1. I can't start build under Developer Command Prompt for VS 2019. We are running build on Jenkins build server. There I just provide options for for MSBuild, and Jenkins plugin executed it in command line, (like Windows batch), see https://wiki.jenkins.io/display/JENKINS/MSBuild+Plugin. Here MSBuild works fine, except when executing with metrics-related option, new way related to VS2019 and roslyn compilers. By the way, Jenkins build servers are one of the most common way of continuous integration and automated code build and release, and latest Visual Studio 2019 -related changes affected a lot of companies.
rainersigwald commented 5 years ago

Is that output from your Jenkins server, or your machine?

You can run arbitrary scripts in Jenkins, though you may have to avoid using the MSBuild plugin there to work around this issue.

gremlm commented 5 years ago

Yes, I can execute scripts. under Jenkins. The problem is that "devenv.exe /Build" (see https://docs.microsoft.com/en-us/visualstudio/ide/reference/build-devenv-exe?view=vs-2019) does not have options for such tasks as

and thus, it can't be used. MSBuild provides such options.

rainersigwald commented 5 years ago

Don't use devenv.exe /build if at all possible. What I was saying is that you can run a script like

@echo off
setlocal enabledelayedexpansion

for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.Component.MSBuild -find Common7\Tools\VsDevCmd.bat`) do (
  cmd /c "call "%%i" && msbuild.exe {something}"
  exit /b !errorlevel!
)
gremlm commented 5 years ago

Thanks for idea, but take a look: I have tried the following right now:

REM -- SPECIAL MSBuild Script @echo off setlocal enabledelayedexpansion

for /f "usebackq tokens=*" %%i in ("%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.Component.MSBuild -find Common7\Tools\VsDevCmd.bat) do ( "%%i" && msbuild.exe /p:Configuration=Debug /t:Metrics /p:MetricsOutputFile="MetricsOutput.xml" exit /b !errorlevel! )

It failed:


Visual Studio 2019 Developer Command Prompt v16.2.0 Copyright (c) 2019 Microsoft Corporation


'msbuild.exe' is not recognized as an internal or external command, operable program or batch file. Build step 'Execute Windows batch command' marked build as failure

rainersigwald commented 5 years ago

Sorry. Updated the earlier post with a correction (explicit cmd /c invocation and quoting).

gremlm commented 5 years ago

Thank you, now it works! I will use this temporary solution for now till this issue will be fixed and released.

Let me know when it will be released and as part of what package, Visual Studio 2019 update or Visual Studio Build tools.

aleksei-saharov commented 4 years ago

@rainersigwald, is it possible to have this PR merged? I also faced with the same issue on TeamCity Build Agent. Now I need to call

MSBuildLocator.QueryVisualStudioInstances()
    .Where(instance => File.Exists(Path.Combine(instance.MSBuildPath, "MSBuild.exe")))
    .OrderByDescending(instance => instance.Version).FirstOrDefault();

It works locally and on TC, but this solution is not really nice to me.