ソースを参照

Merge pull request #96146 from raulsntos/dotnet/resolve-hostfxr-path-from-command-line

C#: Resolve the hostfxr path using dotnet CLI
Thaddeus Crews 3 ヶ月 前
コミット
0cd7bb51e9
1 ファイル変更58 行追加17 行削除
  1. 58 17
      modules/mono/mono_gd/gd_mono.cpp

+ 58 - 17
modules/mono/mono_gd/gd_mono.cpp

@@ -40,6 +40,7 @@
 
 #ifdef TOOLS_ENABLED
 #include "../editor/hostfxr_resolver.h"
+#include "../editor/semver.h"
 #endif
 
 #include "core/config/project_settings.h"
@@ -105,6 +106,60 @@ const char_t *get_data(const HostFxrCharString &p_char_str) {
 	return (const char_t *)p_char_str.get_data();
 }
 
+#ifdef TOOLS_ENABLED
+bool try_get_dotnet_root_from_command_line(String &r_dotnet_root) {
+	String pipe;
+	List<String> args;
+	args.push_back("--list-sdks");
+
+	int exitcode;
+	Error err = OS::get_singleton()->execute("dotnet", args, &pipe, &exitcode, true);
+
+	ERR_FAIL_COND_V_MSG(err != OK, false, String(".NET failed to get list of installed SDKs. Error: ") + error_names[err]);
+	ERR_FAIL_COND_V_MSG(exitcode != 0, false, pipe);
+
+	Vector<String> sdks = pipe.strip_edges().replace("\r\n", "\n").split("\n", false);
+
+	godotsharp::SemVerParser sem_ver_parser;
+
+	godotsharp::SemVer latest_sdk_version;
+	String latest_sdk_path;
+
+	for (const String &sdk : sdks) {
+		// The format of the SDK lines is:
+		// 8.0.401 [/usr/share/dotnet/sdk]
+		String version_string = sdk.get_slice(" ", 0);
+		String path = sdk.get_slice(" ", 1);
+		path = path.substr(1, path.length() - 2);
+
+		godotsharp::SemVer version;
+		if (!sem_ver_parser.parse(version_string, version)) {
+			WARN_PRINT("Unable to parse .NET SDK version '" + version_string + "'.");
+			continue;
+		}
+
+		if (!DirAccess::exists(path)) {
+			WARN_PRINT("Found .NET SDK version '" + version_string + "' with invalid path '" + path + "'.");
+			continue;
+		}
+
+		if (version > latest_sdk_version) {
+			latest_sdk_version = version;
+			latest_sdk_path = path;
+		}
+	}
+
+	if (!latest_sdk_path.is_empty()) {
+		print_verbose("Found .NET SDK at " + latest_sdk_path);
+		// The `dotnet_root` is the parent directory.
+		r_dotnet_root = latest_sdk_path.path_join("..").simplify_path();
+		return true;
+	}
+
+	return false;
+}
+#endif
+
 String find_hostfxr() {
 #ifdef TOOLS_ENABLED
 	String dotnet_root;
@@ -113,23 +168,9 @@ String find_hostfxr() {
 		return fxr_path;
 	}
 
-	// hostfxr_resolver doesn't look for dotnet in `PATH`. If it fails, we try to find the dotnet
-	// executable in `PATH` here and pass its location as `dotnet_root` to `get_hostfxr_path`.
-	String dotnet_exe = Path::find_executable("dotnet");
-
-	if (!dotnet_exe.is_empty()) {
-		// The file found in PATH may be a symlink
-		dotnet_exe = Path::abspath(Path::realpath(dotnet_exe));
-
-		// TODO:
-		// Sometimes, the symlink may not point to the dotnet executable in the dotnet root.
-		// That's the case with snaps. The snap install should have been found with the
-		// previous `get_hostfxr_path`, but it would still be better to do this properly
-		// and use something like `dotnet --list-sdks/runtimes` to find the actual location.
-		// This way we could also check if the proper sdk or runtime is installed. This would
-		// allow us to fail gracefully and show some helpful information in the editor.
-
-		dotnet_root = dotnet_exe.get_base_dir();
+	// hostfxr_resolver doesn't look for dotnet in `PATH`. If it fails, we try to use the dotnet
+	// executable in `PATH` to find the `dotnet_root` and get the `hostfxr_path` from there.
+	if (try_get_dotnet_root_from_command_line(dotnet_root)) {
 		if (godotsharp::hostfxr_resolver::try_get_path_from_dotnet_root(dotnet_root, fxr_path)) {
 			return fxr_path;
 		}