Skip to content

Commit 121de39

Browse files
committed
Move hostfxr-related code into a separate module
1 parent 3375964 commit 121de39

File tree

9 files changed

+186
-117
lines changed

9 files changed

+186
-117
lines changed

gm_dotnet_native/CMakeLists.txt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,19 @@ set(NET_CORE_VERSION "1.0.0" CACHE STRING "Version of bundled .NET Core Runtime"
2121

2222
#Project name
2323
project(gm_dotnet_native)
24-
add_library(gm_dotnet_native SHARED src/gm_dotnet.cpp dotnethelper-src/cleanup_function_type.h utils/get_exe_path.cpp)
25-
add_library(dotnethelper SHARED dotnethelper-src/dotnethelper.cpp dotnethelper-src/cleanup_function_type.h
26-
dotnethelper-src/LuaAPIExposure.h dotnethelper-src/LuaAPIExposure.cpp utils/get_exe_path.cpp)
24+
add_library(gm_dotnet_native SHARED
25+
src/gm_dotnet.cpp
26+
dotnethelper-src/cleanup_function_type.h
27+
utils/path.cpp
28+
)
29+
add_library(dotnethelper SHARED
30+
dotnethelper-src/dotnethelper.cpp
31+
dotnethelper-src/cleanup_function_type.h
32+
dotnethelper-src/LuaAPIExposure.h
33+
dotnethelper-src/LuaAPIExposure.cpp
34+
dotnethelper-src/hostfxr_interop.cpp
35+
utils/path.cpp
36+
)
2737
#Set up external include libraries
2838
include_directories ("${EXTERNAL_INCLUDES_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}")
2939
add_subdirectory ("${EXTERNAL_INCLUDES_PATH}/dynalo")

gm_dotnet_native/dotnethelper-src/dotnethelper.cpp

Lines changed: 4 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,22 @@
66
#include <iostream>
77
#include <string>
88
#include <GarrysMod/Lua/LuaBase.h>
9-
#include <dynalo/dynalo.hpp>
10-
#include <netcore/coreclr_delegates.h>
119
#include "LuaAPIExposure.h"
1210
#include "cleanup_function_type.h"
13-
#include "hostfxr_loader.h"
14-
#include "utils/get_exe_path.h"
11+
#include "hostfxr_interop.h"
12+
#include "utils/path.h"
1513
#ifdef WIN32
1614
#include <Windows.h>
1715
#else
1816
#include <cstring>
19-
#include <dlfcn.h>
20-
#include <unistd.h>
2117
#endif
2218

2319
#ifdef WIN32
2420
#define DYNAMIC_EXPORT _declspec(dllexport)
25-
#define __T(x) L##x
2621
#else
2722
#define DYNAMIC_EXPORT __attribute__((visibility("default")))
28-
#define __T(x) x
2923
#endif
3024

31-
#define _T(x) __T(x)
32-
3325
typedef int (*managed_delegate_executor_fn)(lua_State* luaState);
3426

3527
typedef cleanup_function_fn (*managed_main_fn)(GarrysMod::Lua::ILuaBase* lua,
@@ -46,9 +38,6 @@ std::ofstream error_log_file;
4638
managed_delegate_executor_fn managed_delegate_executor = nullptr;
4739
managed_main_fn managed_main = nullptr;
4840

49-
const std::filesystem::path lua_bin_folder = _T("garrysmod/lua/bin");
50-
const dynalo::library hostfxr_library(lua_bin_folder / _T("dotnet/host/fxr") / NET_CORE_VERSION / dynalo::to_native_name("hostfxr"));
51-
5241
void HOSTFXR_CALLTYPE dotnet_error_writer(const char_t* message)
5342
{
5443
error_log_file << message << std::endl;
@@ -130,72 +119,6 @@ void* params_to_managed_code[] = {
130119
};
131120
// clang-format on
132121

133-
hostfxr_handle get_runtime_environment_handle(const hostfxr_functions& hostfxr)
134-
{
135-
const auto dotnet_root_path = (std::filesystem::current_path() / lua_bin_folder / _T("dotnet")).make_preferred();
136-
std::filesystem::path game_exe_path = utils::get_exe_path();
137-
138-
hostfxr_initialize_parameters dotnet_runtime_params;
139-
dotnet_runtime_params.size = sizeof(hostfxr_initialize_parameters);
140-
dotnet_runtime_params.host_path = game_exe_path.c_str();
141-
dotnet_runtime_params.dotnet_root = dotnet_root_path.c_str();
142-
143-
const auto gmodnet_dll_relative_path = lua_bin_folder / _T("gmodnet/GmodNET.dll");
144-
const char_t* dotnet_args[] = {_T("exec"), gmodnet_dll_relative_path.c_str()};
145-
146-
hostfxr_handle result = nullptr;
147-
int error_code = hostfxr.initialize_for_dotnet_command_line(static_cast<int>(std::size(dotnet_args)),
148-
dotnet_args,
149-
&dotnet_runtime_params,
150-
&result);
151-
if(error_code != 0)
152-
{
153-
throw std::runtime_error(std::string("Unable to initialize dotnet runtime. Error code: ") + std::to_string(error_code));
154-
}
155-
if(result == nullptr)
156-
{
157-
throw std::runtime_error("runtime_environment_handle is null");
158-
}
159-
160-
return result;
161-
}
162-
163-
get_function_pointer_fn get_dotnet_runtime_delegate(const hostfxr_functions& hostfxr, hostfxr_handle runtime_environment_handle)
164-
{
165-
get_function_pointer_fn result = nullptr;
166-
int error_code = hostfxr.get_runtime_delegate(runtime_environment_handle, hdt_get_function_pointer, reinterpret_cast<void**>(&result));
167-
if(error_code != 0)
168-
{
169-
throw std::runtime_error(std::string("Unable to get delegate of dotnet runtime. Error code: ") + std::to_string(error_code));
170-
}
171-
if(result == nullptr)
172-
{
173-
throw std::runtime_error("get_function_pointer is null");
174-
}
175-
176-
return result;
177-
}
178-
179-
managed_main_fn load_gmodnet_main(get_function_pointer_fn get_function_pointer)
180-
{
181-
managed_main_fn result = nullptr;
182-
int error_code = get_function_pointer(_T("GmodNET.Startup, GmodNET"),
183-
_T("Main"),
184-
UNMANAGEDCALLERSONLY_METHOD,
185-
nullptr,
186-
nullptr,
187-
reinterpret_cast<void**>(&result));
188-
if(error_code != 0)
189-
{
190-
throw std::runtime_error(std::string("Unable to load managed entry point: Error code: ") + std::to_string(error_code));
191-
}
192-
if(result == nullptr)
193-
{
194-
throw std::runtime_error("Unable to load managed entry point: managed_main is null");
195-
}
196-
return result;
197-
}
198-
199122
extern "C" DYNAMIC_EXPORT cleanup_function_fn InitNetRuntime(GarrysMod::Lua::ILuaBase* lua)
200123
{
201124
if(!error_log_file.is_open())
@@ -207,11 +130,9 @@ extern "C" DYNAMIC_EXPORT cleanup_function_fn InitNetRuntime(GarrysMod::Lua::ILu
207130
{
208131
try
209132
{
210-
hostfxr_functions hostfxr(hostfxr_library);
133+
hostfxr_interop hostfxr{};
211134
hostfxr.set_error_writer(dotnet_error_writer);
212-
hostfxr_handle runtime_environment_handle = get_runtime_environment_handle(hostfxr);
213-
get_function_pointer_fn get_function_pointer = get_dotnet_runtime_delegate(hostfxr, runtime_environment_handle);
214-
managed_main = load_gmodnet_main(get_function_pointer);
135+
managed_main = hostfxr.load_gmodnet_main<managed_main_fn>();
215136
}
216137
catch(const std::runtime_error& ex)
217138
{
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#include "hostfxr_interop.h"
2+
#include <type_traits>
3+
#include <dynalo/dynalo.hpp>
4+
#include "utils/path.h"
5+
6+
#ifdef WIN32
7+
#define STRINGIZE _CRT_STRINGIZE
8+
#else
9+
#define STRINGIZE_(x) #x
10+
#define STRINGIZE(x) STRINGIZE_(x)
11+
#endif
12+
13+
const std::filesystem::path dotnet_folder("dotnet");
14+
const std::filesystem::path gmodnet_dll_path("gmodnet/GmodNET.dll");
15+
const dynalo::library hostfxr_library(utils::path::lua_bin_folder / _T("dotnet/host/fxr") / NET_CORE_VERSION
16+
/ dynalo::to_native_name("hostfxr"));
17+
18+
hostfxr_interop::hostfxr_interop()
19+
{
20+
#define LOAD_FN(x) x = hostfxr_library.get_function<std::remove_pointer_t<hostfxr_##x##_fn>>(STRINGIZE(hostfxr_##x))
21+
22+
LOAD_FN(initialize_for_dotnet_command_line);
23+
LOAD_FN(get_runtime_delegate);
24+
LOAD_FN(set_error_writer);
25+
26+
#undef LOAD_FN
27+
}
28+
29+
hostfxr_handle hostfxr_interop::init_runtime_for_gmodnet()
30+
{
31+
const auto dotnet_root_path = (std::filesystem::current_path() / utils::path::lua_bin_folder / dotnet_folder).make_preferred();
32+
std::filesystem::path game_exe_path = utils::path::get_exe();
33+
34+
hostfxr_initialize_parameters dotnet_runtime_params;
35+
dotnet_runtime_params.size = sizeof(hostfxr_initialize_parameters);
36+
dotnet_runtime_params.host_path = game_exe_path.c_str();
37+
dotnet_runtime_params.dotnet_root = dotnet_root_path.c_str();
38+
39+
const auto gmodnet_dll_relative_path = utils::path::lua_bin_folder / gmodnet_dll_path;
40+
const char_t* dotnet_args[] = {_T("exec"), gmodnet_dll_relative_path.c_str()};
41+
42+
return validate_call<hostfxr_handle>(
43+
[&](auto* result) {
44+
return initialize_for_dotnet_command_line(static_cast<int>(std::size(dotnet_args)), dotnet_args, &dotnet_runtime_params, result);
45+
},
46+
"hostfxr_handle",
47+
"Unable to initialize dotnet runtime");
48+
}
49+
50+
get_function_pointer_fn hostfxr_interop::managed_function_pointer_getter()
51+
{
52+
hostfxr_handle runtime_environment_handle = init_runtime_for_gmodnet();
53+
return validate_call<get_function_pointer_fn>(
54+
[&](auto* result) {
55+
return get_runtime_delegate(runtime_environment_handle, hdt_get_function_pointer, reinterpret_cast<void**>(result));
56+
},
57+
"get_function_pointer",
58+
"Unable to get delegate of dotnet runtime");
59+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#pragma once
2+
3+
#include <filesystem>
4+
#include <functional>
5+
#include <netcore/hostfxr.h>
6+
#include <netcore/coreclr_delegates.h>
7+
8+
#ifdef WIN32
9+
#define __T(x) L##x
10+
#else
11+
#define __T(x) x
12+
#endif
13+
14+
#define _T(x) __T(x)
15+
16+
class hostfxr_interop
17+
{
18+
public:
19+
explicit hostfxr_interop();
20+
21+
template<typename T>
22+
T load_gmodnet_main();
23+
24+
hostfxr_set_error_writer_fn set_error_writer{};
25+
26+
private:
27+
template<typename T>
28+
T validate_call(const std::function<int(T*)>& function_call, const std::string& result_name, const std::string& error_msg);
29+
hostfxr_handle init_runtime_for_gmodnet();
30+
get_function_pointer_fn managed_function_pointer_getter();
31+
32+
private:
33+
hostfxr_initialize_for_dotnet_command_line_fn initialize_for_dotnet_command_line{};
34+
hostfxr_get_runtime_delegate_fn get_runtime_delegate{};
35+
};
36+
37+
#include "hostfxr_interop_p.h"
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// hostfxr_interop's template method definitions
2+
3+
template<typename T>
4+
T hostfxr_interop::validate_call(const std::function<int(T*)>& function_call, const std::string& result_name, const std::string& error_msg)
5+
{
6+
static_assert(std::is_pointer_v<T>, "T must be a pointer type");
7+
8+
T result = nullptr;
9+
int error_code = function_call(&result);
10+
if(error_code != 0)
11+
{
12+
throw std::runtime_error(error_msg + " (error code: " + std::to_string(error_code) + ")");
13+
}
14+
if(result == nullptr)
15+
{
16+
throw std::runtime_error(result_name + " is null");
17+
}
18+
19+
return result;
20+
}
21+
22+
template<typename T>
23+
T hostfxr_interop::load_gmodnet_main()
24+
{
25+
get_function_pointer_fn get_function_pointer = managed_function_pointer_getter();
26+
27+
return validate_call<T>(
28+
[&](auto* result) {
29+
return get_function_pointer(_T("GmodNET.Startup, GmodNET"),
30+
_T("Main"),
31+
UNMANAGEDCALLERSONLY_METHOD,
32+
nullptr,
33+
nullptr,
34+
reinterpret_cast<void**>(result));
35+
},
36+
"managed_main",
37+
"Unable to load managed entry point");
38+
}

gm_dotnet_native/dotnethelper-src/hostfxr_loader.h

Lines changed: 0 additions & 29 deletions
This file was deleted.

gm_dotnet_native/linux-helper-src/segv_signal_handler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include <execinfo.h>
88
#include <unistd.h>
99
#include <regex>
10-
#include "utils/get_exe_path.h"
10+
#include "utils/path.h"
1111

1212
using namespace std;
1313

@@ -57,7 +57,7 @@ extern "C" __attribute__((__visibility__("default"))) void install_sigsegv_handl
5757
{
5858
if(!WasHandlerSet)
5959
{
60-
std::filesystem::path exe_path = utils::get_exe_path();
60+
std::filesystem::path exe_path = utils::path::get_exe();
6161

6262
regex file_matcher = regex(".*\\/gmod$");
6363
if(!regex_match(exe_path.native(), file_matcher))

gm_dotnet_native/utils/path.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "path.h"
2+
#ifdef WIN32
3+
#include <Windows.h>
4+
#else
5+
#include <unistd.h>
6+
#endif
7+
8+
namespace utils::path
9+
{
10+
11+
const std::filesystem::path lua_bin_folder = "garrysmod/lua/bin";
12+
13+
std::filesystem::path get_exe()
14+
{
15+
const int max_name_length = 301;
16+
std::filesystem::path::string_type game_exe_path(max_name_length, '\0');
17+
#ifdef WIN32
18+
GetModuleFileNameW(nullptr, game_exe_path.data(), static_cast<DWORD>(game_exe_path.size()) - 1);
19+
#else
20+
int exe_path_length = readlink("/proc/self/exe", game_exe_path.data(), game_exe_path.size() - 1);
21+
#endif
22+
return game_exe_path;
23+
}
24+
} //namespace utils

gm_dotnet_native/utils/path.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#pragma once
2+
3+
#include <filesystem>
4+
5+
namespace utils::path
6+
{
7+
extern const std::filesystem::path lua_bin_folder;
8+
std::filesystem::path get_exe();
9+
}

0 commit comments

Comments
 (0)