C#: Replace libnethost dependency to find hostfxr
We want to replace libnethost as it gives us issues with some compilers. Our implementation tries to mimic libnethost's hostfxr_resolver search logic. We try to use the same function names for easier comparing in case we need to update this in the future.
This commit is contained in:
parent
4b164b8e47
commit
f784fb2000
11
methods.py
11
methods.py
|
@ -819,21 +819,12 @@ def generate_vs_project(env, num_jobs):
|
||||||
module_configs = ModuleConfigs()
|
module_configs = ModuleConfigs()
|
||||||
|
|
||||||
if env.get("module_mono_enabled"):
|
if env.get("module_mono_enabled"):
|
||||||
import modules.mono.build_scripts.mono_configure as mono_configure
|
mono_defines = [("GD_MONO_HOT_RELOAD",)] if env["tools"] else []
|
||||||
|
|
||||||
app_host_dir = mono_configure.find_dotnet_app_host_dir(env)
|
|
||||||
if app_host_dir and os.path.isdir(app_host_dir):
|
|
||||||
mono_defines = [("NETHOST_USE_AS_STATIC",)]
|
|
||||||
if env["tools"]:
|
|
||||||
mono_defines += [("GD_MONO_HOT_RELOAD",)]
|
|
||||||
module_configs.add_mode(
|
module_configs.add_mode(
|
||||||
"mono",
|
"mono",
|
||||||
includes=app_host_dir,
|
|
||||||
cli_args="module_mono_enabled=yes",
|
cli_args="module_mono_enabled=yes",
|
||||||
defines=mono_defines,
|
defines=mono_defines,
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
print(".NET App Host directory not found. Generated project will not have build variants for .NET.")
|
|
||||||
|
|
||||||
env["MSVSBUILDCOM"] = module_configs.build_commandline("scons")
|
env["MSVSBUILDCOM"] = module_configs.build_commandline("scons")
|
||||||
env["MSVSREBUILDCOM"] = module_configs.build_commandline("scons vsproj=yes")
|
env["MSVSREBUILDCOM"] = module_configs.build_commandline("scons vsproj=yes")
|
||||||
|
|
|
@ -7,8 +7,8 @@ set -uo pipefail
|
||||||
|
|
||||||
# Loops through all code files tracked by Git.
|
# Loops through all code files tracked by Git.
|
||||||
git ls-files -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.m' '*.mm' '*.inc' '*.java' '*.glsl' \
|
git ls-files -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.m' '*.mm' '*.inc' '*.java' '*.glsl' \
|
||||||
':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' \
|
':!:.git/*' ':!:thirdparty/*' ':!:*/thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' \
|
||||||
':!:tests/python_build/*' |
|
':!:*-so_wrap.*' ':!:tests/python_build/*' |
|
||||||
while read -r f; do
|
while read -r f; do
|
||||||
# Run clang-format.
|
# Run clang-format.
|
||||||
clang-format --Wno-error=unknown -i "$f"
|
clang-format --Wno-error=unknown -i "$f"
|
||||||
|
|
|
@ -27,293 +27,3 @@ def configure(env, env_mono):
|
||||||
|
|
||||||
if env["tools"]:
|
if env["tools"]:
|
||||||
env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"])
|
env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"])
|
||||||
|
|
||||||
app_host_dir = find_dotnet_app_host_dir(env)
|
|
||||||
|
|
||||||
def check_app_host_file_exists(file):
|
|
||||||
file_path = os.path.join(app_host_dir, file)
|
|
||||||
if not os.path.isfile(file_path):
|
|
||||||
raise RuntimeError("File not found: " + file_path)
|
|
||||||
|
|
||||||
# TODO:
|
|
||||||
# All libnethost does for us is provide a function to find hostfxr.
|
|
||||||
# If we could handle that logic ourselves we could void linking it.
|
|
||||||
|
|
||||||
# nethost file names:
|
|
||||||
# static: libnethost.a/lib
|
|
||||||
# shared: libnethost.a/dylib and nethost.dll
|
|
||||||
check_app_host_file_exists("libnethost.lib" if os.name == "nt" else "libnethost.a")
|
|
||||||
check_app_host_file_exists("nethost.h")
|
|
||||||
check_app_host_file_exists("hostfxr.h")
|
|
||||||
check_app_host_file_exists("coreclr_delegates.h")
|
|
||||||
|
|
||||||
env_mono.Prepend(CPPPATH=app_host_dir)
|
|
||||||
|
|
||||||
env.Append(LIBPATH=[app_host_dir])
|
|
||||||
|
|
||||||
# Only the editor build links nethost, which is needed to find hostfxr.
|
|
||||||
# Exported games don't need this logic as hostfxr is bundled with them.
|
|
||||||
if tools_enabled:
|
|
||||||
libnethost_path = os.path.join(app_host_dir, "libnethost.lib" if os.name == "nt" else "libnethost.a")
|
|
||||||
|
|
||||||
if env["platform"] == "windows":
|
|
||||||
env_mono.Append(CPPDEFINES=["NETHOST_USE_AS_STATIC"])
|
|
||||||
|
|
||||||
if env.msvc:
|
|
||||||
env.Append(LINKFLAGS="libnethost.lib")
|
|
||||||
else:
|
|
||||||
env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"])
|
|
||||||
else:
|
|
||||||
is_apple = env["platform"] in ["macos", "ios"]
|
|
||||||
# is_macos = is_apple and not is_ios
|
|
||||||
|
|
||||||
# if is_ios and not is_ios_sim:
|
|
||||||
# env_mono.Append(CPPDEFINES=["IOS_DEVICE"])
|
|
||||||
|
|
||||||
if is_apple:
|
|
||||||
env.Append(LINKFLAGS=["-Wl,-force_load," + libnethost_path])
|
|
||||||
else:
|
|
||||||
env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"])
|
|
||||||
|
|
||||||
|
|
||||||
def find_dotnet_app_host_dir(env):
|
|
||||||
dotnet_version = "6.0"
|
|
||||||
|
|
||||||
dotnet_root = env["dotnet_root"]
|
|
||||||
|
|
||||||
if not dotnet_root:
|
|
||||||
dotnet_cmd = find_dotnet_executable(env["arch"])
|
|
||||||
if dotnet_cmd:
|
|
||||||
sdk_path = find_dotnet_sdk(dotnet_cmd, dotnet_version)
|
|
||||||
if sdk_path:
|
|
||||||
dotnet_root = os.path.abspath(os.path.join(sdk_path, os.pardir))
|
|
||||||
|
|
||||||
if not dotnet_root:
|
|
||||||
raise RuntimeError("Cannot find .NET Core Sdk")
|
|
||||||
|
|
||||||
print("Found .NET Core Sdk root directory: " + dotnet_root)
|
|
||||||
|
|
||||||
dotnet_cmd = os.path.join(dotnet_root, "dotnet.exe" if os.name == "nt" else "dotnet")
|
|
||||||
|
|
||||||
runtime_identifier = determine_runtime_identifier(env)
|
|
||||||
|
|
||||||
# TODO: In the future, if it can't be found this way, we want to obtain it
|
|
||||||
# from the runtime.{runtime_identifier}.Microsoft.NETCore.DotNetAppHost NuGet package.
|
|
||||||
app_host_version = find_app_host_version(dotnet_cmd, dotnet_version)
|
|
||||||
if not app_host_version:
|
|
||||||
raise RuntimeError("Cannot find .NET app host for version: " + dotnet_version)
|
|
||||||
|
|
||||||
def get_runtime_path():
|
|
||||||
return os.path.join(
|
|
||||||
dotnet_root,
|
|
||||||
"packs",
|
|
||||||
"Microsoft.NETCore.App.Host." + runtime_identifier,
|
|
||||||
app_host_version,
|
|
||||||
"runtimes",
|
|
||||||
runtime_identifier,
|
|
||||||
"native",
|
|
||||||
)
|
|
||||||
|
|
||||||
app_host_dir = get_runtime_path()
|
|
||||||
|
|
||||||
# Some Linux distros use their distro name as the RID in these paths.
|
|
||||||
# If the initial generic path doesn't exist, try to get the RID from `dotnet --info`.
|
|
||||||
# The generic RID should still be the first choice. Some platforms like Windows 10
|
|
||||||
# define the RID as `win10-x64` but still use the generic `win-x64` for directory names.
|
|
||||||
if not app_host_dir or not os.path.isdir(app_host_dir):
|
|
||||||
runtime_identifier = find_dotnet_cli_rid(dotnet_cmd)
|
|
||||||
app_host_dir = get_runtime_path()
|
|
||||||
|
|
||||||
return app_host_dir
|
|
||||||
|
|
||||||
|
|
||||||
def determine_runtime_identifier(env):
|
|
||||||
# The keys are Godot's names, the values are the Microsoft's names.
|
|
||||||
# List: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
|
|
||||||
names_map = {
|
|
||||||
"windows": "win",
|
|
||||||
"macos": "osx",
|
|
||||||
"linuxbsd": "linux",
|
|
||||||
}
|
|
||||||
arch_map = {
|
|
||||||
"x86_64": "x64",
|
|
||||||
"x86_32": "x86",
|
|
||||||
"arm64": "arm64",
|
|
||||||
"arm32": "arm",
|
|
||||||
}
|
|
||||||
platform = env["platform"]
|
|
||||||
if is_desktop(platform):
|
|
||||||
return "%s-%s" % (names_map[platform], arch_map[env["arch"]])
|
|
||||||
else:
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
|
|
||||||
def find_app_host_version(dotnet_cmd, search_version_str):
|
|
||||||
import subprocess
|
|
||||||
from distutils.version import LooseVersion
|
|
||||||
|
|
||||||
search_version = LooseVersion(search_version_str)
|
|
||||||
found_match = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
|
|
||||||
lines = subprocess.check_output([dotnet_cmd, "--list-runtimes"], env=env).splitlines()
|
|
||||||
|
|
||||||
for line_bytes in lines:
|
|
||||||
line = line_bytes.decode("utf-8")
|
|
||||||
if not line.startswith("Microsoft.NETCore.App "):
|
|
||||||
continue
|
|
||||||
|
|
||||||
parts = line.split(" ", 2)
|
|
||||||
if len(parts) < 3:
|
|
||||||
continue
|
|
||||||
|
|
||||||
version_str = parts[1]
|
|
||||||
|
|
||||||
version = LooseVersion(version_str)
|
|
||||||
|
|
||||||
if version >= search_version:
|
|
||||||
search_version = version
|
|
||||||
found_match = True
|
|
||||||
if found_match:
|
|
||||||
return str(search_version)
|
|
||||||
except (subprocess.CalledProcessError, OSError) as e:
|
|
||||||
import sys
|
|
||||||
|
|
||||||
print(e, file=sys.stderr)
|
|
||||||
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
def find_dotnet_arch(dotnet_cmd):
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
try:
|
|
||||||
env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
|
|
||||||
lines = subprocess.check_output([dotnet_cmd, "--info"], env=env).splitlines()
|
|
||||||
|
|
||||||
for line_bytes in lines:
|
|
||||||
line = line_bytes.decode("utf-8")
|
|
||||||
|
|
||||||
parts = line.split(":", 1)
|
|
||||||
if len(parts) < 2:
|
|
||||||
continue
|
|
||||||
|
|
||||||
arch_str = parts[0].strip()
|
|
||||||
if arch_str != "Architecture":
|
|
||||||
continue
|
|
||||||
|
|
||||||
arch_value = parts[1].strip()
|
|
||||||
arch_map = {"x64": "x86_64", "x86": "x86_32", "arm64": "arm64", "arm32": "arm32"}
|
|
||||||
return arch_map[arch_value]
|
|
||||||
except (subprocess.CalledProcessError, OSError) as e:
|
|
||||||
import sys
|
|
||||||
|
|
||||||
print(e, file=sys.stderr)
|
|
||||||
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
def find_dotnet_sdk(dotnet_cmd, search_version_str):
|
|
||||||
import subprocess
|
|
||||||
from distutils.version import LooseVersion
|
|
||||||
|
|
||||||
search_version = LooseVersion(search_version_str)
|
|
||||||
|
|
||||||
try:
|
|
||||||
env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
|
|
||||||
lines = subprocess.check_output([dotnet_cmd, "--list-sdks"], env=env).splitlines()
|
|
||||||
|
|
||||||
for line_bytes in lines:
|
|
||||||
line = line_bytes.decode("utf-8")
|
|
||||||
|
|
||||||
parts = line.split(" ", 1)
|
|
||||||
if len(parts) < 2:
|
|
||||||
continue
|
|
||||||
|
|
||||||
version_str = parts[0]
|
|
||||||
|
|
||||||
version = LooseVersion(version_str)
|
|
||||||
|
|
||||||
if version < search_version:
|
|
||||||
continue
|
|
||||||
|
|
||||||
path_part = parts[1]
|
|
||||||
return path_part[1 : path_part.find("]")]
|
|
||||||
except (subprocess.CalledProcessError, OSError) as e:
|
|
||||||
import sys
|
|
||||||
|
|
||||||
print(e, file=sys.stderr)
|
|
||||||
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
def find_dotnet_cli_rid(dotnet_cmd):
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
try:
|
|
||||||
env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
|
|
||||||
lines = subprocess.check_output([dotnet_cmd, "--info"], env=env).splitlines()
|
|
||||||
|
|
||||||
for line_bytes in lines:
|
|
||||||
line = line_bytes.decode("utf-8")
|
|
||||||
if not line.startswith(" RID:"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
parts = line.split()
|
|
||||||
if len(parts) < 2:
|
|
||||||
continue
|
|
||||||
|
|
||||||
return parts[1]
|
|
||||||
except (subprocess.CalledProcessError, OSError) as e:
|
|
||||||
import sys
|
|
||||||
|
|
||||||
print(e, file=sys.stderr)
|
|
||||||
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
ENV_PATH_SEP = ";" if os.name == "nt" else ":"
|
|
||||||
|
|
||||||
|
|
||||||
def find_dotnet_executable(arch):
|
|
||||||
is_windows = os.name == "nt"
|
|
||||||
windows_exts = os.environ["PATHEXT"].split(ENV_PATH_SEP) if is_windows else None
|
|
||||||
path_dirs = os.environ["PATH"].split(ENV_PATH_SEP)
|
|
||||||
|
|
||||||
search_dirs = path_dirs + [os.getcwd()] # cwd is last in the list
|
|
||||||
|
|
||||||
for dir in path_dirs:
|
|
||||||
search_dirs += [
|
|
||||||
os.path.join(dir, "x64"),
|
|
||||||
os.path.join(dir, "x86"),
|
|
||||||
os.path.join(dir, "arm64"),
|
|
||||||
os.path.join(dir, "arm32"),
|
|
||||||
] # search subfolders for cross compiling
|
|
||||||
|
|
||||||
# `dotnet --info` may not specify architecture. In such cases,
|
|
||||||
# we fallback to the first one we find without architecture.
|
|
||||||
sdk_path_unknown_arch = ""
|
|
||||||
|
|
||||||
for dir in search_dirs:
|
|
||||||
path = os.path.join(dir, "dotnet")
|
|
||||||
|
|
||||||
if is_windows:
|
|
||||||
for extension in windows_exts:
|
|
||||||
path_with_ext = path + extension
|
|
||||||
|
|
||||||
if os.path.isfile(path_with_ext) and os.access(path_with_ext, os.X_OK):
|
|
||||||
sdk_arch = find_dotnet_arch(path_with_ext)
|
|
||||||
if sdk_arch == arch or arch == "":
|
|
||||||
return path_with_ext
|
|
||||||
elif sdk_arch == "":
|
|
||||||
sdk_path_unknown_arch = path_with_ext
|
|
||||||
else:
|
|
||||||
if os.path.isfile(path) and os.access(path, os.X_OK):
|
|
||||||
sdk_arch = find_dotnet_arch(path)
|
|
||||||
if sdk_arch == arch or arch == "":
|
|
||||||
return path
|
|
||||||
elif sdk_arch == "":
|
|
||||||
sdk_path_unknown_arch = path
|
|
||||||
|
|
||||||
return sdk_path_unknown_arch
|
|
||||||
|
|
|
@ -4,23 +4,13 @@ supported_platforms = ["windows", "macos", "linuxbsd"]
|
||||||
|
|
||||||
|
|
||||||
def can_build(env, platform):
|
def can_build(env, platform):
|
||||||
return not env["arch"].startswith("rv")
|
if env["arch"].startswith("rv"):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if env["tools"]:
|
||||||
|
env.module_add_dependencies("mono", ["regex"])
|
||||||
|
|
||||||
def get_opts(platform):
|
return True
|
||||||
from SCons.Variables import BoolVariable, PathVariable
|
|
||||||
|
|
||||||
default_mono_static = platform in ["ios", "web"]
|
|
||||||
default_mono_bundles_zlib = platform in ["web"]
|
|
||||||
|
|
||||||
return [
|
|
||||||
PathVariable(
|
|
||||||
"dotnet_root",
|
|
||||||
"Path to the .NET Sdk installation directory for the target platform and architecture",
|
|
||||||
"",
|
|
||||||
PathVariable.PathAccept,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def configure(env):
|
def configure(env):
|
||||||
|
|
|
@ -0,0 +1,335 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* hostfxr_resolver.cpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Adapted to Godot from the nethost library: https://github.com/dotnet/runtime/tree/main/src/native/corehost
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) .NET Foundation and Contributors
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hostfxr_resolver.h"
|
||||||
|
|
||||||
|
#include "core/config/engine.h"
|
||||||
|
#include "core/io/dir_access.h"
|
||||||
|
#include "core/io/file_access.h"
|
||||||
|
#include "core/os/os.h"
|
||||||
|
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../utils/path_utils.h"
|
||||||
|
#include "semver.h"
|
||||||
|
|
||||||
|
// We don't use libnethost as it gives us issues with some compilers.
|
||||||
|
// This file tries to mimic libnethost's hostfxr_resolver search logic. We try to use the
|
||||||
|
// same function names for easier comparing in case we need to update this in the future.
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
String get_hostfxr_file_name() {
|
||||||
|
#if defined(WINDOWS_ENABLED) || defined(UWP_ENABLED)
|
||||||
|
return "hostfxr.dll";
|
||||||
|
#elif defined(OSX_ENABLED) || defined(IOS_ENABLED)
|
||||||
|
return "libhostfxr.dylib";
|
||||||
|
#else
|
||||||
|
return "libhostfxr.so";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_latest_fxr(const String &fxr_root, String &r_fxr_path) {
|
||||||
|
godotsharp::SemVerParser sem_ver_parser;
|
||||||
|
|
||||||
|
bool found_ver = false;
|
||||||
|
godotsharp::SemVer latest_ver;
|
||||||
|
String latest_ver_str;
|
||||||
|
|
||||||
|
Ref<DirAccess> da = DirAccess::open(fxr_root);
|
||||||
|
da->list_dir_begin();
|
||||||
|
for (String dir = da->get_next(); !dir.is_empty(); dir = da->get_next()) {
|
||||||
|
if (!da->current_is_dir() || dir == "." || dir == "..") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ver = dir.get_file();
|
||||||
|
|
||||||
|
godotsharp::SemVer fx_ver;
|
||||||
|
if (sem_ver_parser.parse(ver, fx_ver)) {
|
||||||
|
if (!found_ver || fx_ver > latest_ver) {
|
||||||
|
latest_ver = fx_ver;
|
||||||
|
latest_ver_str = ver;
|
||||||
|
found_ver = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_ver) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fxr_with_ver = path::join(fxr_root, latest_ver_str);
|
||||||
|
String hostfxr_file_path = path::join(fxr_with_ver, get_hostfxr_file_name());
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V_MSG(!FileAccess::exists(hostfxr_file_path), false, "Missing hostfxr library in directory: " + fxr_with_ver);
|
||||||
|
|
||||||
|
r_fxr_path = hostfxr_file_path;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
|
||||||
|
|
||||||
|
BOOL is_wow64() {
|
||||||
|
BOOL wow64 = FALSE;
|
||||||
|
|
||||||
|
LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
|
||||||
|
|
||||||
|
if (fnIsWow64Process) {
|
||||||
|
if (!fnIsWow64Process(GetCurrentProcess(), &wow64)) {
|
||||||
|
wow64 = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wow64;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char *arch_name_map[][2] = {
|
||||||
|
{ "arm32", "arm" },
|
||||||
|
{ "arm64", "arm64" },
|
||||||
|
{ "rv64", "riscv64" },
|
||||||
|
{ "x86_64", "x64" },
|
||||||
|
{ "x86_32", "x86" },
|
||||||
|
{ nullptr, nullptr }
|
||||||
|
};
|
||||||
|
|
||||||
|
String get_dotnet_arch() {
|
||||||
|
String arch = Engine::get_singleton()->get_architecture_name();
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
while (arch_name_map[idx][0] != nullptr) {
|
||||||
|
if (arch_name_map[idx][0] == arch) {
|
||||||
|
return arch_name_map[idx][1];
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_default_installation_dir(String &r_dotnet_root) {
|
||||||
|
#if defined(WINDOWS_ENABLED)
|
||||||
|
String program_files_env;
|
||||||
|
if (is_wow64()) {
|
||||||
|
// Running x86 on x64, looking for x86 install
|
||||||
|
program_files_env = "ProgramFiles(x86)";
|
||||||
|
} else {
|
||||||
|
program_files_env = "ProgramFiles";
|
||||||
|
}
|
||||||
|
|
||||||
|
String program_files_dir = OS::get_singleton()->get_environment(program_files_env);
|
||||||
|
|
||||||
|
if (program_files_dir.is_empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
|
||||||
|
// When emulating x64 on arm
|
||||||
|
String dotnet_root_emulated = path::join(program_files_dir, "dotnet", "x64");
|
||||||
|
if (FileAccess::exists(path::join(dotnet_root_emulated, "dotnet.exe"))) {
|
||||||
|
r_dotnet_root = dotnet_root_emulated;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
r_dotnet_root = path::join(program_files_dir, "dotnet");
|
||||||
|
return true;
|
||||||
|
#elif defined(TARGET_OSX)
|
||||||
|
r_dotnet_root = "/usr/local/share/dotnet";
|
||||||
|
|
||||||
|
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
|
||||||
|
// When emulating x64 on arm
|
||||||
|
String dotnet_root_emulated = path::join(r_dotnet_root, "x64");
|
||||||
|
if (FileAccess::exists(path::join(dotnet_root_emulated, "dotnet"))) {
|
||||||
|
r_dotnet_root = dotnet_root_emulated;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
r_dotnet_root = "/usr/share/dotnet";
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_install_location_from_file(const String &p_file_path, String &r_dotnet_root) {
|
||||||
|
Error err = OK;
|
||||||
|
Ref<FileAccess> f = FileAccess::open(p_file_path, FileAccess::READ, &err);
|
||||||
|
|
||||||
|
if (f.is_null() || err != OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String line = f->get_line();
|
||||||
|
|
||||||
|
if (line.is_empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
r_dotnet_root = line;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_dotnet_self_registered_dir(String &r_dotnet_root) {
|
||||||
|
#if defined(WINDOWS_ENABLED)
|
||||||
|
String sub_key = "SOFTWARE\\dotnet\\Setup\\InstalledVersions\\" + get_dotnet_arch();
|
||||||
|
Char16String value = String("InstallLocation").utf16();
|
||||||
|
|
||||||
|
HKEY hkey = NULL;
|
||||||
|
LSTATUS result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR)(sub_key.utf16().get_data()), 0, KEY_READ | KEY_WOW64_32KEY, &hkey);
|
||||||
|
if (result != ERROR_SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD size = 0;
|
||||||
|
result = RegGetValueW(hkey, nullptr, (LPCWSTR)(value.get_data()), RRF_RT_REG_SZ, nullptr, nullptr, &size);
|
||||||
|
if (result != ERROR_SUCCESS || size == 0) {
|
||||||
|
RegCloseKey(hkey);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<WCHAR> buffer;
|
||||||
|
buffer.resize(size / sizeof(WCHAR));
|
||||||
|
result = RegGetValueW(hkey, nullptr, (LPCWSTR)(value.get_data()), RRF_RT_REG_SZ, nullptr, (LPBYTE)buffer.ptrw(), &size);
|
||||||
|
if (result != ERROR_SUCCESS) {
|
||||||
|
RegCloseKey(hkey);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
r_dotnet_root = String::utf16((const char16_t *)buffer.ptr());
|
||||||
|
RegCloseKey(hkey);
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
String install_location_file = path::join("/etc/dotnet", "install_location_" + get_dotnet_arch().to_lower());
|
||||||
|
if (get_install_location_from_file(install_location_file, r_dotnet_root)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FileAccess::exists(install_location_file)) {
|
||||||
|
// Don't try with the legacy location, this will fall back to the hard-coded default install location
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String legacy_install_location_file = path::join("/etc/dotnet", "install_location");
|
||||||
|
return get_install_location_from_file(legacy_install_location_file, r_dotnet_root);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_file_path_from_env(const String &p_env_key, String &r_dotnet_root) {
|
||||||
|
String env_value = OS::get_singleton()->get_environment(p_env_key);
|
||||||
|
|
||||||
|
if (!env_value.is_empty()) {
|
||||||
|
env_value = path::realpath(env_value);
|
||||||
|
|
||||||
|
if (DirAccess::exists(env_value)) {
|
||||||
|
r_dotnet_root = env_value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_dotnet_root_from_env(String &r_dotnet_root) {
|
||||||
|
String dotnet_root_env = "DOTNET_ROOT";
|
||||||
|
String arch_for_env = get_dotnet_arch();
|
||||||
|
|
||||||
|
if (!arch_for_env.is_empty()) {
|
||||||
|
// DOTNET_ROOT_<arch>
|
||||||
|
if (get_file_path_from_env(dotnet_root_env + "_" + arch_for_env.to_upper(), r_dotnet_root)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
// WoW64-only: DOTNET_ROOT(x86)
|
||||||
|
if (is_wow64() && get_file_path_from_env("DOTNET_ROOT(x86)", r_dotnet_root)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// DOTNET_ROOT
|
||||||
|
return get_file_path_from_env(dotnet_root_env, r_dotnet_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
} //namespace
|
||||||
|
|
||||||
|
bool godotsharp::hostfxr_resolver::try_get_path_from_dotnet_root(const String &p_dotnet_root, String &r_fxr_path) {
|
||||||
|
String fxr_dir = path::join(p_dotnet_root, "host", "fxr");
|
||||||
|
ERR_FAIL_COND_V_MSG(!DirAccess::exists(fxr_dir), false, "The host fxr folder does not exist: " + fxr_dir);
|
||||||
|
return get_latest_fxr(fxr_dir, r_fxr_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool godotsharp::hostfxr_resolver::try_get_path(String &r_dotnet_root, String &r_fxr_path) {
|
||||||
|
if (!get_dotnet_root_from_env(r_dotnet_root) &&
|
||||||
|
!get_dotnet_self_registered_dir(r_dotnet_root) &&
|
||||||
|
!get_default_installation_dir(r_dotnet_root)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return try_get_path_from_dotnet_root(r_dotnet_root, r_fxr_path);
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* hostfxr_resolver.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef HOSTFXR_RESOLVER_H
|
||||||
|
#define HOSTFXR_RESOLVER_H
|
||||||
|
|
||||||
|
#include "core/string/ustring.h"
|
||||||
|
|
||||||
|
namespace godotsharp {
|
||||||
|
namespace hostfxr_resolver {
|
||||||
|
|
||||||
|
bool try_get_path_from_dotnet_root(const String &p_dotnet_root, String &r_out_fxr_path);
|
||||||
|
bool try_get_path(String &r_out_dotnet_root, String &r_out_fxr_path);
|
||||||
|
|
||||||
|
} //namespace hostfxr_resolver
|
||||||
|
} //namespace godotsharp
|
||||||
|
|
||||||
|
#endif // HOSTFXR_RESOLVER_H
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* semver.cpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#include "semver.h"
|
||||||
|
|
||||||
|
bool godotsharp::SemVer::parse_digit_only_field(const String &p_field, uint64_t &r_result) {
|
||||||
|
if (p_field.is_empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t integer = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < p_field.length(); i++) {
|
||||||
|
char32_t c = p_field[i];
|
||||||
|
if (is_digit(c)) {
|
||||||
|
bool overflow = ((uint64_t)integer > UINT64_MAX / 10) || ((uint64_t)integer == UINT64_MAX / 10 && c > '5');
|
||||||
|
ERR_FAIL_COND_V_MSG(overflow, false, "Cannot represent '" + p_field + "' as a 64-bit unsigned integer, since the value is too large.");
|
||||||
|
integer *= 10;
|
||||||
|
integer += c - '0';
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r_result = (uint64_t)integer;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int godotsharp::SemVer::cmp(const godotsharp::SemVer &p_a, const godotsharp::SemVer &p_b) {
|
||||||
|
if (p_a.major != p_b.major) {
|
||||||
|
return p_a.major > p_b.major ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_a.minor != p_b.minor) {
|
||||||
|
return p_a.minor > p_b.minor ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_a.patch != p_b.patch) {
|
||||||
|
return p_a.patch > p_b.patch ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_a.prerelease.is_empty() && p_b.prerelease.is_empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_a.prerelease.is_empty() || p_b.prerelease.is_empty()) {
|
||||||
|
return p_a.prerelease.is_empty() ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_a.prerelease != p_b.prerelease) {
|
||||||
|
// This could be optimized, but I'm too lazy
|
||||||
|
|
||||||
|
Vector<String> a_field_set = p_a.prerelease.split(".");
|
||||||
|
Vector<String> b_field_set = p_b.prerelease.split(".");
|
||||||
|
|
||||||
|
int a_field_count = a_field_set.size();
|
||||||
|
int b_field_count = b_field_set.size();
|
||||||
|
|
||||||
|
int min_field_count = MIN(a_field_count, b_field_count);
|
||||||
|
|
||||||
|
for (int i = 0; i < min_field_count; i++) {
|
||||||
|
const String &a_field = a_field_set[i];
|
||||||
|
const String &b_field = b_field_set[i];
|
||||||
|
|
||||||
|
if (a_field == b_field) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t a_num;
|
||||||
|
bool a_is_digit_only = parse_digit_only_field(a_field, a_num);
|
||||||
|
|
||||||
|
uint64_t b_num;
|
||||||
|
bool b_is_digit_only = parse_digit_only_field(b_field, b_num);
|
||||||
|
|
||||||
|
if (a_is_digit_only && b_is_digit_only) {
|
||||||
|
// Identifiers consisting of only digits are compared numerically.
|
||||||
|
|
||||||
|
if (a_num == b_num) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a_num > b_num ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a_is_digit_only || b_is_digit_only) {
|
||||||
|
// Numeric identifiers always have lower precedence than non-numeric identifiers.
|
||||||
|
return b_is_digit_only ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identifiers with letters or hyphens are compared lexically in ASCII sort order.
|
||||||
|
return a_field > b_field ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a_field_count != b_field_count) {
|
||||||
|
// A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal.
|
||||||
|
return a_field_count > b_field_count ? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool godotsharp::SemVerParser::parse(const String &p_ver_text, godotsharp::SemVer &r_semver) {
|
||||||
|
if (!regex.is_valid() && regex.get_pattern().is_empty()) {
|
||||||
|
regex.compile("^(?P<major>0|[1-9]\\d*)\\.(?P<minor>0|[1-9]\\d*)\\.(?P<patch>0|[1-9]\\d*)(?:-(?P<prerelease>(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$");
|
||||||
|
ERR_FAIL_COND_V(!regex.is_valid(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<RegExMatch> match = regex.search(p_ver_text);
|
||||||
|
|
||||||
|
if (match.is_valid()) {
|
||||||
|
r_semver = SemVer(
|
||||||
|
match->get_string("major").to_int(),
|
||||||
|
match->get_string("minor").to_int(),
|
||||||
|
match->get_string("patch").to_int(),
|
||||||
|
match->get_string("prerelease"),
|
||||||
|
match->get_string("buildmetadata"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* semver.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef SEMVER_H
|
||||||
|
#define SEMVER_H
|
||||||
|
|
||||||
|
#include "core/string/ustring.h"
|
||||||
|
#include "modules/regex/regex.h"
|
||||||
|
|
||||||
|
// <sys/sysmacros.h> is included somewhere, which defines major(dev) to gnu_dev_major(dev)
|
||||||
|
#if defined(major)
|
||||||
|
#undef major
|
||||||
|
#endif
|
||||||
|
#if defined(minor)
|
||||||
|
#undef minor
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace godotsharp {
|
||||||
|
|
||||||
|
struct SemVer {
|
||||||
|
private:
|
||||||
|
static bool parse_digit_only_field(const String &p_field, uint64_t &r_result);
|
||||||
|
|
||||||
|
static int cmp(const SemVer &p_a, const SemVer &p_b);
|
||||||
|
|
||||||
|
public:
|
||||||
|
int major = 0;
|
||||||
|
int minor = 0;
|
||||||
|
int patch = 0;
|
||||||
|
String prerelease;
|
||||||
|
String build_metadata;
|
||||||
|
|
||||||
|
bool operator==(const SemVer &b) const {
|
||||||
|
return cmp(*this, b) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const SemVer &b) const {
|
||||||
|
return !operator==(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const SemVer &b) const {
|
||||||
|
return cmp(*this, b) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>(const SemVer &b) const {
|
||||||
|
return cmp(*this, b) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(const SemVer &b) const {
|
||||||
|
return cmp(*this, b) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(const SemVer &b) const {
|
||||||
|
return cmp(*this, b) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SemVer() {}
|
||||||
|
|
||||||
|
SemVer(int p_major, int p_minor, int p_patch,
|
||||||
|
const String &p_prerelease, const String &p_build_metadata) :
|
||||||
|
major(p_major),
|
||||||
|
minor(p_minor),
|
||||||
|
patch(p_patch),
|
||||||
|
prerelease(p_prerelease),
|
||||||
|
build_metadata(p_build_metadata) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SemVerParser {
|
||||||
|
private:
|
||||||
|
RegEx regex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool parse(const String &p_ver_text, SemVer &r_semver);
|
||||||
|
};
|
||||||
|
|
||||||
|
} //namespace godotsharp
|
||||||
|
|
||||||
|
#endif // SEMVER_H
|
|
@ -43,12 +43,13 @@
|
||||||
#include "../utils/path_utils.h"
|
#include "../utils/path_utils.h"
|
||||||
#include "gd_mono_cache.h"
|
#include "gd_mono_cache.h"
|
||||||
|
|
||||||
|
#include "../thirdparty/coreclr_delegates.h"
|
||||||
|
#include "../thirdparty/hostfxr.h"
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
#include <nethost.h>
|
#include "../editor/hostfxr_resolver.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <coreclr_delegates.h>
|
|
||||||
#include <hostfxr.h>
|
|
||||||
#ifdef UNIX_ENABLED
|
#ifdef UNIX_ENABLED
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -88,50 +89,20 @@ HostFxrCharString str_to_hostfxr(const String &p_str) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
|
||||||
String str_from_hostfxr(const char_t *p_buffer) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
return String::utf16((const char16_t *)p_buffer);
|
|
||||||
#else
|
|
||||||
return String::utf8((const char *)p_buffer);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char_t *get_data(const HostFxrCharString &p_char_str) {
|
const char_t *get_data(const HostFxrCharString &p_char_str) {
|
||||||
return (const char_t *)p_char_str.get_data();
|
return (const char_t *)p_char_str.get_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
|
||||||
String find_hostfxr(size_t p_known_buffer_size, get_hostfxr_parameters *p_get_hostfxr_params) {
|
|
||||||
// Pre-allocate a large buffer for the path to hostfxr
|
|
||||||
Vector<char_t> buffer;
|
|
||||||
buffer.resize(p_known_buffer_size);
|
|
||||||
|
|
||||||
int rc = get_hostfxr_path(buffer.ptrw(), &p_known_buffer_size, p_get_hostfxr_params);
|
|
||||||
|
|
||||||
ERR_FAIL_COND_V_MSG(rc != 0, String(), "get_hostfxr_path failed with code: " + itos(rc));
|
|
||||||
|
|
||||||
return str_from_hostfxr(buffer.ptr());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
String find_hostfxr() {
|
String find_hostfxr() {
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
const int CoreHostLibMissingFailure = 0x80008083;
|
String dotnet_root;
|
||||||
const int HostApiBufferTooSmall = 0x80008098;
|
String fxr_path;
|
||||||
|
if (godotsharp::hostfxr_resolver::try_get_path(dotnet_root, fxr_path)) {
|
||||||
size_t buffer_size = 0;
|
return fxr_path;
|
||||||
int rc = get_hostfxr_path(nullptr, &buffer_size, nullptr);
|
|
||||||
|
|
||||||
if (rc == HostApiBufferTooSmall) {
|
|
||||||
return find_hostfxr(buffer_size, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == CoreHostLibMissingFailure) {
|
// hostfxr_resolver doesn't look for dotnet in `PATH`. If it fails, we try to find the dotnet
|
||||||
// Apparently `get_hostfxr_path` doesn't look for dotnet in `PATH`? (I suppose it needs the
|
// executable in `PATH` here and pass its location as `dotnet_root` to `get_hostfxr_path`.
|
||||||
// `DOTNET_ROOT` environment variable). If it fails, we try to find the dotnet executable
|
|
||||||
// in `PATH` ourselves and pass its location as `dotnet_root` to `get_hostfxr_path`.
|
|
||||||
String dotnet_exe = path::find_executable("dotnet");
|
String dotnet_exe = path::find_executable("dotnet");
|
||||||
|
|
||||||
if (!dotnet_exe.is_empty()) {
|
if (!dotnet_exe.is_empty()) {
|
||||||
|
@ -146,27 +117,15 @@ String find_hostfxr() {
|
||||||
// This way we could also check if the proper sdk or runtime is installed. This would
|
// 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.
|
// allow us to fail gracefully and show some helpful information in the editor.
|
||||||
|
|
||||||
HostFxrCharString dotnet_root = str_to_hostfxr(dotnet_exe.get_base_dir());
|
dotnet_root = dotnet_exe.get_base_dir();
|
||||||
|
if (godotsharp::hostfxr_resolver::try_get_path_from_dotnet_root(dotnet_root, fxr_path)) {
|
||||||
get_hostfxr_parameters get_hostfxr_parameters = {
|
return fxr_path;
|
||||||
sizeof(get_hostfxr_parameters),
|
|
||||||
nullptr,
|
|
||||||
get_data(dotnet_root)
|
|
||||||
};
|
|
||||||
|
|
||||||
buffer_size = 0;
|
|
||||||
rc = get_hostfxr_path(nullptr, &buffer_size, &get_hostfxr_parameters);
|
|
||||||
if (rc == HostApiBufferTooSmall) {
|
|
||||||
return find_hostfxr(buffer_size, &get_hostfxr_parameters);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == CoreHostLibMissingFailure) {
|
|
||||||
ERR_PRINT(String() + ".NET: One of the dependent libraries is missing. " +
|
ERR_PRINT(String() + ".NET: One of the dependent libraries is missing. " +
|
||||||
"Typically when the `hostfxr`, `hostpolicy` or `coreclr` dynamic " +
|
"Typically when the `hostfxr`, `hostpolicy` or `coreclr` dynamic " +
|
||||||
"libraries are not present in the expected locations.");
|
"libraries are not present in the expected locations.");
|
||||||
}
|
|
||||||
|
|
||||||
return String();
|
return String();
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
#ifndef __CORECLR_DELEGATES_H__
|
||||||
|
#define __CORECLR_DELEGATES_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define CORECLR_DELEGATE_CALLTYPE __stdcall
|
||||||
|
#ifdef _WCHAR_T_DEFINED
|
||||||
|
typedef wchar_t char_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned short char_t;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define CORECLR_DELEGATE_CALLTYPE
|
||||||
|
typedef char char_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UNMANAGEDCALLERSONLY_METHOD ((const char_t*)-1)
|
||||||
|
|
||||||
|
// Signature of delegate returned by coreclr_delegate_type::load_assembly_and_get_function_pointer
|
||||||
|
typedef int (CORECLR_DELEGATE_CALLTYPE *load_assembly_and_get_function_pointer_fn)(
|
||||||
|
const char_t *assembly_path /* Fully qualified path to assembly */,
|
||||||
|
const char_t *type_name /* Assembly qualified type name */,
|
||||||
|
const char_t *method_name /* Public static method name compatible with delegateType */,
|
||||||
|
const char_t *delegate_type_name /* Assembly qualified delegate type name or null
|
||||||
|
or UNMANAGEDCALLERSONLY_METHOD if the method is marked with
|
||||||
|
the UnmanagedCallersOnlyAttribute. */,
|
||||||
|
void *reserved /* Extensibility parameter (currently unused and must be 0) */,
|
||||||
|
/*out*/ void **delegate /* Pointer where to store the function pointer result */);
|
||||||
|
|
||||||
|
// Signature of delegate returned by load_assembly_and_get_function_pointer_fn when delegate_type_name == null (default)
|
||||||
|
typedef int (CORECLR_DELEGATE_CALLTYPE *component_entry_point_fn)(void *arg, int32_t arg_size_in_bytes);
|
||||||
|
|
||||||
|
typedef int (CORECLR_DELEGATE_CALLTYPE *get_function_pointer_fn)(
|
||||||
|
const char_t *type_name /* Assembly qualified type name */,
|
||||||
|
const char_t *method_name /* Public static method name compatible with delegateType */,
|
||||||
|
const char_t *delegate_type_name /* Assembly qualified delegate type name or null,
|
||||||
|
or UNMANAGEDCALLERSONLY_METHOD if the method is marked with
|
||||||
|
the UnmanagedCallersOnlyAttribute. */,
|
||||||
|
void *load_context /* Extensibility parameter (currently unused and must be 0) */,
|
||||||
|
void *reserved /* Extensibility parameter (currently unused and must be 0) */,
|
||||||
|
/*out*/ void **delegate /* Pointer where to store the function pointer result */);
|
||||||
|
|
||||||
|
#endif // __CORECLR_DELEGATES_H__
|
|
@ -0,0 +1,323 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
#ifndef __HOSTFXR_H__
|
||||||
|
#define __HOSTFXR_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define HOSTFXR_CALLTYPE __cdecl
|
||||||
|
#ifdef _WCHAR_T_DEFINED
|
||||||
|
typedef wchar_t char_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned short char_t;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define HOSTFXR_CALLTYPE
|
||||||
|
typedef char char_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum hostfxr_delegate_type
|
||||||
|
{
|
||||||
|
hdt_com_activation,
|
||||||
|
hdt_load_in_memory_assembly,
|
||||||
|
hdt_winrt_activation,
|
||||||
|
hdt_com_register,
|
||||||
|
hdt_com_unregister,
|
||||||
|
hdt_load_assembly_and_get_function_pointer,
|
||||||
|
hdt_get_function_pointer,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_main_fn)(const int argc, const char_t **argv);
|
||||||
|
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_main_startupinfo_fn)(
|
||||||
|
const int argc,
|
||||||
|
const char_t **argv,
|
||||||
|
const char_t *host_path,
|
||||||
|
const char_t *dotnet_root,
|
||||||
|
const char_t *app_path);
|
||||||
|
typedef int32_t(HOSTFXR_CALLTYPE* hostfxr_main_bundle_startupinfo_fn)(
|
||||||
|
const int argc,
|
||||||
|
const char_t** argv,
|
||||||
|
const char_t* host_path,
|
||||||
|
const char_t* dotnet_root,
|
||||||
|
const char_t* app_path,
|
||||||
|
int64_t bundle_header_offset);
|
||||||
|
|
||||||
|
typedef void(HOSTFXR_CALLTYPE *hostfxr_error_writer_fn)(const char_t *message);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Sets a callback which is to be used to write errors to.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// error_writer
|
||||||
|
// A callback function which will be invoked every time an error is to be reported.
|
||||||
|
// Or nullptr to unregister previously registered callback and return to the default behavior.
|
||||||
|
// Return value:
|
||||||
|
// The previously registered callback (which is now unregistered), or nullptr if no previous callback
|
||||||
|
// was registered
|
||||||
|
//
|
||||||
|
// The error writer is registered per-thread, so the registration is thread-local. On each thread
|
||||||
|
// only one callback can be registered. Subsequent registrations overwrite the previous ones.
|
||||||
|
//
|
||||||
|
// By default no callback is registered in which case the errors are written to stderr.
|
||||||
|
//
|
||||||
|
// Each call to the error writer is sort of like writing a single line (the EOL character is omitted).
|
||||||
|
// Multiple calls to the error writer may occur for one failure.
|
||||||
|
//
|
||||||
|
// If the hostfxr invokes functions in hostpolicy as part of its operation, the error writer
|
||||||
|
// will be propagated to hostpolicy for the duration of the call. This means that errors from
|
||||||
|
// both hostfxr and hostpolicy will be reporter through the same error writer.
|
||||||
|
//
|
||||||
|
typedef hostfxr_error_writer_fn(HOSTFXR_CALLTYPE *hostfxr_set_error_writer_fn)(hostfxr_error_writer_fn error_writer);
|
||||||
|
|
||||||
|
typedef void* hostfxr_handle;
|
||||||
|
struct hostfxr_initialize_parameters
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
const char_t *host_path;
|
||||||
|
const char_t *dotnet_root;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initializes the hosting components for a dotnet command line running an application
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// argc
|
||||||
|
// Number of argv arguments
|
||||||
|
// argv
|
||||||
|
// Command-line arguments for running an application (as if through the dotnet executable).
|
||||||
|
// Only command-line arguments which are accepted by runtime installation are supported, SDK/CLI commands are not supported.
|
||||||
|
// For example 'app.dll app_argument_1 app_argument_2`.
|
||||||
|
// parameters
|
||||||
|
// Optional. Additional parameters for initialization
|
||||||
|
// host_context_handle
|
||||||
|
// On success, this will be populated with an opaque value representing the initialized host context
|
||||||
|
//
|
||||||
|
// Return value:
|
||||||
|
// Success - Hosting components were successfully initialized
|
||||||
|
// HostInvalidState - Hosting components are already initialized
|
||||||
|
//
|
||||||
|
// This function parses the specified command-line arguments to determine the application to run. It will
|
||||||
|
// then find the corresponding .runtimeconfig.json and .deps.json with which to resolve frameworks and
|
||||||
|
// dependencies and prepare everything needed to load the runtime.
|
||||||
|
//
|
||||||
|
// This function only supports arguments for running an application. It does not support SDK commands.
|
||||||
|
//
|
||||||
|
// This function does not load the runtime.
|
||||||
|
//
|
||||||
|
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_initialize_for_dotnet_command_line_fn)(
|
||||||
|
int argc,
|
||||||
|
const char_t **argv,
|
||||||
|
const struct hostfxr_initialize_parameters *parameters,
|
||||||
|
/*out*/ hostfxr_handle *host_context_handle);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initializes the hosting components using a .runtimeconfig.json file
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// runtime_config_path
|
||||||
|
// Path to the .runtimeconfig.json file
|
||||||
|
// parameters
|
||||||
|
// Optional. Additional parameters for initialization
|
||||||
|
// host_context_handle
|
||||||
|
// On success, this will be populated with an opaque value representing the initialized host context
|
||||||
|
//
|
||||||
|
// Return value:
|
||||||
|
// Success - Hosting components were successfully initialized
|
||||||
|
// Success_HostAlreadyInitialized - Config is compatible with already initialized hosting components
|
||||||
|
// Success_DifferentRuntimeProperties - Config has runtime properties that differ from already initialized hosting components
|
||||||
|
// CoreHostIncompatibleConfig - Config is incompatible with already initialized hosting components
|
||||||
|
//
|
||||||
|
// This function will process the .runtimeconfig.json to resolve frameworks and prepare everything needed
|
||||||
|
// to load the runtime. It will only process the .deps.json from frameworks (not any app/component that
|
||||||
|
// may be next to the .runtimeconfig.json).
|
||||||
|
//
|
||||||
|
// This function does not load the runtime.
|
||||||
|
//
|
||||||
|
// If called when the runtime has already been loaded, this function will check if the specified runtime
|
||||||
|
// config is compatible with the existing runtime.
|
||||||
|
//
|
||||||
|
// Both Success_HostAlreadyInitialized and Success_DifferentRuntimeProperties codes are considered successful
|
||||||
|
// initializations. In the case of Success_DifferentRuntimeProperties, it is left to the consumer to verify that
|
||||||
|
// the difference in properties is acceptable.
|
||||||
|
//
|
||||||
|
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_initialize_for_runtime_config_fn)(
|
||||||
|
const char_t *runtime_config_path,
|
||||||
|
const struct hostfxr_initialize_parameters *parameters,
|
||||||
|
/*out*/ hostfxr_handle *host_context_handle);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Gets the runtime property value for an initialized host context
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// host_context_handle
|
||||||
|
// Handle to the initialized host context
|
||||||
|
// name
|
||||||
|
// Runtime property name
|
||||||
|
// value
|
||||||
|
// Out parameter. Pointer to a buffer with the property value.
|
||||||
|
//
|
||||||
|
// Return value:
|
||||||
|
// The error code result.
|
||||||
|
//
|
||||||
|
// The buffer pointed to by value is owned by the host context. The lifetime of the buffer is only
|
||||||
|
// guaranteed until any of the below occur:
|
||||||
|
// - a 'run' method is called for the host context
|
||||||
|
// - properties are changed via hostfxr_set_runtime_property_value
|
||||||
|
// - the host context is closed via 'hostfxr_close'
|
||||||
|
//
|
||||||
|
// If host_context_handle is nullptr and an active host context exists, this function will get the
|
||||||
|
// property value for the active host context.
|
||||||
|
//
|
||||||
|
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_property_value_fn)(
|
||||||
|
const hostfxr_handle host_context_handle,
|
||||||
|
const char_t *name,
|
||||||
|
/*out*/ const char_t **value);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Sets the value of a runtime property for an initialized host context
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// host_context_handle
|
||||||
|
// Handle to the initialized host context
|
||||||
|
// name
|
||||||
|
// Runtime property name
|
||||||
|
// value
|
||||||
|
// Value to set
|
||||||
|
//
|
||||||
|
// Return value:
|
||||||
|
// The error code result.
|
||||||
|
//
|
||||||
|
// Setting properties is only supported for the first host context, before the runtime has been loaded.
|
||||||
|
//
|
||||||
|
// If the property already exists in the host context, it will be overwritten. If value is nullptr, the
|
||||||
|
// property will be removed.
|
||||||
|
//
|
||||||
|
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_set_runtime_property_value_fn)(
|
||||||
|
const hostfxr_handle host_context_handle,
|
||||||
|
const char_t *name,
|
||||||
|
const char_t *value);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Gets all the runtime properties for an initialized host context
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// host_context_handle
|
||||||
|
// Handle to the initialized host context
|
||||||
|
// count
|
||||||
|
// [in] Size of the keys and values buffers
|
||||||
|
// [out] Number of properties returned (size of keys/values buffers used). If the input value is too
|
||||||
|
// small or keys/values is nullptr, this is populated with the number of available properties
|
||||||
|
// keys
|
||||||
|
// Array of pointers to buffers with runtime property keys
|
||||||
|
// values
|
||||||
|
// Array of pointers to buffers with runtime property values
|
||||||
|
//
|
||||||
|
// Return value:
|
||||||
|
// The error code result.
|
||||||
|
//
|
||||||
|
// The buffers pointed to by keys and values are owned by the host context. The lifetime of the buffers is only
|
||||||
|
// guaranteed until any of the below occur:
|
||||||
|
// - a 'run' method is called for the host context
|
||||||
|
// - properties are changed via hostfxr_set_runtime_property_value
|
||||||
|
// - the host context is closed via 'hostfxr_close'
|
||||||
|
//
|
||||||
|
// If host_context_handle is nullptr and an active host context exists, this function will get the
|
||||||
|
// properties for the active host context.
|
||||||
|
//
|
||||||
|
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_properties_fn)(
|
||||||
|
const hostfxr_handle host_context_handle,
|
||||||
|
/*inout*/ size_t * count,
|
||||||
|
/*out*/ const char_t **keys,
|
||||||
|
/*out*/ const char_t **values);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Load CoreCLR and run the application for an initialized host context
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// host_context_handle
|
||||||
|
// Handle to the initialized host context
|
||||||
|
//
|
||||||
|
// Return value:
|
||||||
|
// If the app was successfully run, the exit code of the application. Otherwise, the error code result.
|
||||||
|
//
|
||||||
|
// The host_context_handle must have been initialized using hostfxr_initialize_for_dotnet_command_line.
|
||||||
|
//
|
||||||
|
// This function will not return until the managed application exits.
|
||||||
|
//
|
||||||
|
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_run_app_fn)(const hostfxr_handle host_context_handle);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Gets a typed delegate from the currently loaded CoreCLR or from a newly created one.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// host_context_handle
|
||||||
|
// Handle to the initialized host context
|
||||||
|
// type
|
||||||
|
// Type of runtime delegate requested
|
||||||
|
// delegate
|
||||||
|
// An out parameter that will be assigned the delegate.
|
||||||
|
//
|
||||||
|
// Return value:
|
||||||
|
// The error code result.
|
||||||
|
//
|
||||||
|
// If the host_context_handle was initialized using hostfxr_initialize_for_runtime_config,
|
||||||
|
// then all delegate types are supported.
|
||||||
|
// If the host_context_handle was initialized using hostfxr_initialize_for_dotnet_command_line,
|
||||||
|
// then only the following delegate types are currently supported:
|
||||||
|
// hdt_load_assembly_and_get_function_pointer
|
||||||
|
// hdt_get_function_pointer
|
||||||
|
//
|
||||||
|
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_get_runtime_delegate_fn)(
|
||||||
|
const hostfxr_handle host_context_handle,
|
||||||
|
enum hostfxr_delegate_type type,
|
||||||
|
/*out*/ void **delegate);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Closes an initialized host context
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// host_context_handle
|
||||||
|
// Handle to the initialized host context
|
||||||
|
//
|
||||||
|
// Return value:
|
||||||
|
// The error code result.
|
||||||
|
//
|
||||||
|
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_close_fn)(const hostfxr_handle host_context_handle);
|
||||||
|
|
||||||
|
struct hostfxr_dotnet_environment_sdk_info
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
const char_t* version;
|
||||||
|
const char_t* path;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void(HOSTFXR_CALLTYPE* hostfxr_get_dotnet_environment_info_result_fn)(
|
||||||
|
const struct hostfxr_dotnet_environment_info* info,
|
||||||
|
void* result_context);
|
||||||
|
|
||||||
|
struct hostfxr_dotnet_environment_framework_info
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
const char_t* name;
|
||||||
|
const char_t* version;
|
||||||
|
const char_t* path;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hostfxr_dotnet_environment_info
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
const char_t* hostfxr_version;
|
||||||
|
const char_t* hostfxr_commit_hash;
|
||||||
|
|
||||||
|
size_t sdk_count;
|
||||||
|
const struct hostfxr_dotnet_environment_sdk_info* sdks;
|
||||||
|
|
||||||
|
size_t framework_count;
|
||||||
|
const struct hostfxr_dotnet_environment_framework_info* frameworks;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__HOSTFXR_H__
|
Loading…
Reference in New Issue