mono C++ wrapper

This commit is contained in:
Timerix 2024-08-16 19:32:36 +03:00
parent 1859b432df
commit d8e6c69c20
10 changed files with 167 additions and 29 deletions

2
.gitignore vendored
View File

@ -20,4 +20,4 @@ temp/
logs/ logs/
log/ log/
*.log *.log
mono/ ./mono/

1
.vscode/launch.json vendored
View File

@ -11,6 +11,7 @@
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}/bin", "cwd": "${workspaceFolder}/bin",
"externalConsole": false, "externalConsole": false,
"internalConsoleOptions": "neverOpen",
"MIMode": "gdb", "MIMode": "gdb",
"miDebuggerPath": "gdb", "miDebuggerPath": "gdb",
"setupCommands": [ "setupCommands": [

View File

@ -2,7 +2,7 @@
#include <backends/imgui_impl_sdlrenderer2.h> #include <backends/imgui_impl_sdlrenderer2.h>
#include <iostream> #include <iostream>
#include "MainWindow.hpp" #include "MainWindow.hpp"
#include "../exceptions.hpp" #include "exceptions.hpp"
#include "../format.hpp" #include "../format.hpp"
#include "../Resources/fonts.hpp" #include "../Resources/fonts.hpp"
#include "../Resources/textures.hpp" #include "../Resources/textures.hpp"

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "UsefulException.hpp" #include "../UsefulException.hpp"
namespace ougge { namespace ougge {

80
src/Mono/Mono.cpp Normal file
View File

@ -0,0 +1,80 @@
#include "Mono.hpp"
#include "../UsefulException.hpp"
#include "../format.hpp"
#include <mono/jit/jit.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/debug-helpers.h>
#include <iostream>
namespace Mono {
RuntimeJIT::RuntimeJIT(const std::string& domain_name){
mono_set_dirs("mono-libs", "mono-libs");
mono_set_assemblies_path("mono-libs");
mono_config_parse("mono-libs/config.xml");
domain = mono_jit_init(domain_name.c_str());
if(!domain)
throw UsefulException("can't initialize mono domain");
}
RuntimeJIT::~RuntimeJIT(){
mono_jit_cleanup(domain);
}
std::shared_ptr<Assembly> RuntimeJIT::loadAssembly(const std::string &name){
MonoAssembly* ptr = mono_domain_assembly_open(domain, "app.exe");
if(!ptr)
throw UsefulException(format("can't load assembly '%s'", name.c_str()));
return std::make_shared<Assembly>(ptr);
}
Assembly::Assembly(MonoAssembly *ptr)
: ptr(ptr), image(mono_assembly_get_image(ptr))
{
}
Assembly::~Assembly(){
// Tt causes SEGFAULT.
// Is it even possible to unload assembly from domain?
// mono_assembly_close(ptr);
}
std::shared_ptr<Class> Assembly::getClass(const std::string &name_space, const std::string &name){
MonoClass* ptr = mono_class_from_name(image, name_space.c_str(), name.c_str());
if(!ptr)
throw UsefulException(format("can't find class '%s.%s'", name_space.c_str(), name.c_str()));
return std::make_shared<Class>(ptr);
}
Class::Class(MonoClass *ptr)
: ptr(ptr)
{
void* iter = nullptr;
MonoMethod* m = nullptr;
while( (m = mono_class_get_methods(ptr, &iter)) ){
auto name = std::string_view(mono_method_get_name(m));
methods.emplace(std::piecewise_construct,
std::forward_as_tuple(name),
std::forward_as_tuple(name, m));
}
}
template<typename ReturnT, typename... ArgTypes>
std::shared_ptr<std::function<ReturnT(ArgTypes...)>> getMethod(const std::string& name){
return std::make_shared<std::function<ReturnT(ArgTypes...)>>();
}
Method::Method(const std::string_view &name, MonoMethod *ptr)
: ptr(ptr), signature(mono_method_signature(ptr)), name(name)
{
void* iter = nullptr;
MonoType* rt = mono_signature_get_return_type(signature);
MonoType* pt = nullptr;
while( (pt = mono_signature_get_params(signature, &iter)) ){
std::cout<<"name: "<<mono_type_get_name(pt)<<std::endl;
}
}
} // namespace Mono

72
src/Mono/Mono.hpp Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include "../std.hpp"
#include <memory>
#include <string>
#include <functional>
#include <vector>
#include <map>
#include <mono/metadata/metadata.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/object.h>
namespace Mono {
typedef i8 SByte;
typedef u8 Byte;
typedef i16 Short;
typedef u16 UShort;
typedef i32 Int;
typedef i32 UInt;
typedef i64 Long;
typedef i64 ULong;
typedef f32 Float;
typedef f64 Double;
typedef MonoString* String;
class Method {
MonoMethod* ptr;
MonoMethodSignature* signature;
public:
const std::string_view name;
Method(const std::string_view& name, MonoMethod* ptr);
};
class Class {
std::multimap<std::string_view, Method> methods;
MonoClass* ptr;
public:
Class(MonoClass* ptr);
Class(const Class&) = delete;
template<typename ReturnT, typename... ArgTypes>
std::shared_ptr<std::function<ReturnT(ArgTypes...)>> getMethod(const std::string& name);
};
class Assembly {
MonoAssembly* ptr;
MonoImage* image;
public:
Assembly(MonoAssembly* ptr);
Assembly(const Assembly&) = delete;
~Assembly();
std::shared_ptr<Class> getClass(const std::string& name_space, const std::string& name);
};
///LINUX: `config.xml`, `mscorelib.dll`, `libmono-native.so` in `mono-libs` directory
///
///WINDOWS: `config.xml`, `mscorelib.dll` in `mono-libs` directory
class RuntimeJIT {
MonoDomain* domain;
public:
RuntimeJIT(const std::string& domain_name = "MonoApp");
RuntimeJIT(const RuntimeJIT&) = delete;
~RuntimeJIT();
std::shared_ptr<Assembly> loadAssembly(const std::string& name);
};
}

View File

@ -1,6 +1,6 @@
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include "../exceptions.hpp" #include "../UsefulException.hpp"
#include "../format.hpp" #include "../format.hpp"
#include "Resources.hpp" #include "Resources.hpp"
#include "embedded_resources.h" #include "embedded_resources.h"

View File

@ -1,6 +1,6 @@
#include "textures.hpp" #include "textures.hpp"
#include <SDL_image.h> #include <SDL_image.h>
#include "../exceptions.hpp" #include "../GUI/exceptions.hpp"
namespace ougge::Resources { namespace ougge::Resources {

View File

@ -4,10 +4,8 @@
#include "Resources/Resources.hpp" #include "Resources/Resources.hpp"
#include "Game/Scene.hpp" #include "Game/Scene.hpp"
#include "format.hpp" #include "format.hpp"
#include "exceptions.hpp" #include "UsefulException.hpp"
#include <mono/jit/jit.h> #include "Mono/Mono.hpp"
#include <mono/metadata/assembly.h>
#include <mono/metadata/mono-config.h>
using namespace ougge; using namespace ougge;
@ -18,29 +16,16 @@ void update(f64 deltaTime){
int main(int argc, const char** argv){ int main(int argc, const char** argv){
try { try {
Resources::init(); Resources::init();
mono_set_dirs("mono-libs", "mono-libs"); std::cout<<"initialized resource loader"<<std::endl;
mono_set_assemblies_path("mono-libs"); Mono::RuntimeJIT mono;
mono_config_parse("mono-libs/config.xml"); auto a = mono.loadAssembly("app.exe");
std::cout<<"mono_root_dir: "<<mono_assembly_getrootdir()<<std::endl; auto c = a->getClass("", "A");
std::cout<<"mono_config_dir: "<<mono_get_config_dir()<<std::endl; std::cout<<"initialized mono jit runtime"<<std::endl;
MonoDomain* domain = mono_jit_init("myapp");
if(!domain)
throw UsefulException("can't initialize mono domain");
std::cout<<"jit domain initialized"<<std::endl;
MonoAssembly* assembly = mono_domain_assembly_open(domain, "app.exe");
if(!assembly)
throw UsefulException("can't load assembly");
char* mono_argv[] = { "app.exe" };
int mono_argc = 1;
int retval = mono_jit_exec(domain, assembly, mono_argc, mono_argv);
if(retval)
throw new UsefulException(format("managed assembly returned error code: %i", retval));
mono_jit_cleanup(domain);
return 0;
GUI::MainWindow w; GUI::MainWindow w;
w.open("ougge", update); w.open("ougge", update);
std::cout<<"created sdl window"<<std::endl;
w.startUpdateLoop(); w.startUpdateLoop();
std::cout<<"sdl window has been cosed"<<std::endl;
} }
catch(const std::exception& e){ catch(const std::exception& e){
std::cerr<<"Catched exception: "<<e.what()<<std::endl; std::cerr<<"Catched exception: "<<e.what()<<std::endl;