Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

using BackendNativeMethods = Microsoft.Build.BackEnd.NativeMethods;
using Task = System.Threading.Tasks.Task;
using DotNetFrameworkArchitecture = Microsoft.Build.Shared.DotNetFrameworkArchitecture;
using Microsoft.Build.Framework;
using Microsoft.Build.BackEnd.Logging;

Expand Down Expand Up @@ -434,9 +433,9 @@ private Process LaunchNode(string msbuildLocation, string commandLineArgs)

// Repeat the executable name as the first token of the command line because the command line
// parser logic expects it and will otherwise skip the first argument
commandLineArgs = msbuildLocation + " " + commandLineArgs;
commandLineArgs = $"\"{msbuildLocation}\" {commandLineArgs}";

BackendNativeMethods.STARTUP_INFO startInfo = new BackendNativeMethods.STARTUP_INFO();
BackendNativeMethods.STARTUP_INFO startInfo = new();
startInfo.cb = Marshal.SizeOf<BackendNativeMethods.STARTUP_INFO>();

// Null out the process handles so that the parent process does not wait for the child process
Expand Down Expand Up @@ -466,8 +465,8 @@ private Process LaunchNode(string msbuildLocation, string commandLineArgs)
creationFlags |= BackendNativeMethods.CREATE_NEW_CONSOLE;
}

BackendNativeMethods.SECURITY_ATTRIBUTES processSecurityAttributes = new BackendNativeMethods.SECURITY_ATTRIBUTES();
BackendNativeMethods.SECURITY_ATTRIBUTES threadSecurityAttributes = new BackendNativeMethods.SECURITY_ATTRIBUTES();
BackendNativeMethods.SECURITY_ATTRIBUTES processSecurityAttributes = new();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These could be moved into the else block below where its actually used, unless we get rid of the different ways of launching the process in which case this can just go away.

BackendNativeMethods.SECURITY_ATTRIBUTES threadSecurityAttributes = new();
processSecurityAttributes.nLength = Marshal.SizeOf<BackendNativeMethods.SECURITY_ATTRIBUTES>();
threadSecurityAttributes.nLength = Marshal.SizeOf<BackendNativeMethods.SECURITY_ATTRIBUTES>();

Expand All @@ -480,8 +479,8 @@ private Process LaunchNode(string msbuildLocation, string commandLineArgs)
if (!NativeMethodsShared.IsMono)
{
// Run the child process with the same host as the currently-running process.
exeName = GetCurrentHost();
commandLineArgs = "\"" + msbuildLocation + "\" " + commandLineArgs;
string dotnetExe = Path.Combine(FileUtilities.GetFolderAbove(exeName, 2), "dotnet.exe");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a lot going on in this method:

  • On Windows, it uses native methods to launch the process so the path to MSBuild.exe needs to be prepended to the command-line arguments. @rainersigwald do you know why we use a different method to launch the process? The code doesn't seem to need to as far as I can tell. Maybe we can get rid of it?
  • For .NET Core, the command-line arguments must be prepended with the the path to MSBuild.dll and the EXE is dotnet.

I see some missing logic in the current implementation:

  • On Windows, its dotnet.exe, on non-Windows its just dotnet
  • The path to MSBuild.dll is prepended twice on Windows (which technically works but sees dirty)
  • GetCurrentHost() is only ever correct if you run dotnet directly so using it as a fallback seems not great

I would do the following:

  1. Make a method like GetNodeExe() that has all of the logic to find the path to the executable that represents the node, so MSBuild.exe on .NET Framework, dotnet.exe or dotnet for .NET Core.
  2. Make a method like GetNodeArguments() that adjusts the command-line arguments
    Prepend MSBuild.exe on Windows since its using native APIs
    Prepend MSBuild.dll on .NET Core

In my opinion that would simplify this method and make it easier to rationalize what its doing. You could also make these two methods internal and write a unit test to verify they return the correct values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as falling back to GetCurrentHost, I agree it isn't terribly likely to succeed, but I don't think we have a better option. There's a chance someone has fancy logic in their project to make it work, and if we don't fall back to GetCurrentHost, we would break that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure if you don't fall back to current-host our own dogfood builds will fail (they're invoked via dotnet.exe path\to\some\msbuild.dll).

Copy link
Contributor

@jeffkl jeffkl Sep 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetCurrentHost() is only ever correct if you run dotnet directly so using it as a fallback seems not great

Sorry what I meant was having this method here only to use as a fallback, when the entirety of the logic could live inside of it. I did not mean to get rid of the fallback all together. To have solid logic here that then falls back to a method seems clunky is all.

exeName = File.Exists(dotnetExe) ? dotnetExe : GetCurrentHost();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to push this into GetCurrentHost() so we only have to do the file-exists check once?

}
#endif

Expand Down