diff --git a/Source/Editor/Cooker/Steps/DeployDataStep.cpp b/Source/Editor/Cooker/Steps/DeployDataStep.cpp index 4ab3e8669..3332e769e 100644 --- a/Source/Editor/Cooker/Steps/DeployDataStep.cpp +++ b/Source/Editor/Cooker/Steps/DeployDataStep.cpp @@ -176,6 +176,7 @@ bool DeployDataStep::Perform(CookingData& data) FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), packFolder / TEXT("THIRD-PARTY-NOTICES.TXT")); failed |= FileSystem::CopyDirectory(dstDotnet / TEXT("shared/Microsoft.NETCore.App"), srcDotnet / TEXT("../lib/net7.0"), true); failed |= FileSystem::CopyFile(dstDotnet / TEXT("shared/Microsoft.NETCore.App") / TEXT("System.Private.CoreLib.dll"), srcDotnet / TEXT("System.Private.CoreLib.dll")); + // TODO: copy .so/.dll files to native data files (eg. libSystem.IO.Compression.Native.so, libSystem.Native.so, libSystem.Security.Cryptography.Native.Android.so) if (failed) { data.Error(TEXT("Failed to copy .Net runtime data files.")); diff --git a/Source/Editor/CustomEditors/CustomEditorsUtil.cpp b/Source/Editor/CustomEditors/CustomEditorsUtil.cpp index b9f2883a2..cf64d1c83 100644 --- a/Source/Editor/CustomEditors/CustomEditorsUtil.cpp +++ b/Source/Editor/CustomEditors/CustomEditorsUtil.cpp @@ -13,7 +13,7 @@ #include "Engine/Scripting/ManagedCLR/MClass.h" #include "Engine/Scripting/ManagedCLR/MUtils.h" #include "FlaxEngine.Gen.h" -#include +#include #define TRACK_ASSEMBLY(assembly) \ if (assembly->IsLoaded()) \ diff --git a/Source/Editor/Managed/ManagedEditor.Internal.cpp b/Source/Editor/Managed/ManagedEditor.Internal.cpp index 020cb3c61..4f0799b60 100644 --- a/Source/Editor/Managed/ManagedEditor.Internal.cpp +++ b/Source/Editor/Managed/ManagedEditor.Internal.cpp @@ -47,7 +47,7 @@ #include "FlaxEngine.Gen.h" #include "Engine/Level/Actors/AnimatedModel.h" #include "Engine/Serialization/JsonTools.h" -#include +#include Guid ManagedEditor::ObjectID(0x91970b4e, 0x99634f61, 0x84723632, 0x54c776af); diff --git a/Source/Editor/Managed/ManagedEditor.cpp b/Source/Editor/Managed/ManagedEditor.cpp index fdabf9056..da743866f 100644 --- a/Source/Editor/Managed/ManagedEditor.cpp +++ b/Source/Editor/Managed/ManagedEditor.cpp @@ -16,7 +16,7 @@ #include "Engine/Engine/CommandLine.h" #include "Engine/Renderer/ProbesRenderer.h" #include "Engine/Animations/Graph/AnimGraph.h" -#include +#include ManagedEditor::InternalOptions ManagedEditor::ManagedEditorOptions; diff --git a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp index fc3e0d225..6e9156001 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp +++ b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp @@ -14,7 +14,7 @@ #if !COMPILE_WITHOUT_CSHARP #if USE_MONO -#include +#include #endif struct InternalInitData diff --git a/Source/Engine/Content/Asset.cpp b/Source/Engine/Content/Asset.cpp index 5585fbe7e..88003725e 100644 --- a/Source/Engine/Content/Asset.cpp +++ b/Source/Engine/Content/Asset.cpp @@ -14,7 +14,7 @@ #include "Engine/Threading/ConcurrentTaskQueue.h" #if USE_MONO #include "Engine/Scripting/ManagedCLR/MUtils.h" -#include +#include #endif AssetReferenceBase::~AssetReferenceBase() diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp index 1b70152d6..371fd1e99 100644 --- a/Source/Engine/Core/Types/Variant.cpp +++ b/Source/Engine/Core/Types/Variant.cpp @@ -27,7 +27,7 @@ #include "Engine/Utilities/Crc.h" #include "Engine/Utilities/StringConverter.h" #if USE_MONO -#include +#include #endif namespace diff --git a/Source/Engine/Debug/DebugLog.cpp b/Source/Engine/Debug/DebugLog.cpp index d873f4886..a250a7fe3 100644 --- a/Source/Engine/Debug/DebugLog.cpp +++ b/Source/Engine/Debug/DebugLog.cpp @@ -12,8 +12,8 @@ #if USE_MONO -#include -#include +#include +#include namespace Impl { diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp index 335b4cb69..42b4316c9 100644 --- a/Source/Engine/Graphics/Models/Mesh.cpp +++ b/Source/Engine/Graphics/Models/Mesh.cpp @@ -18,7 +18,7 @@ #include "Engine/Renderer/GBufferPass.h" #endif #if USE_MONO -#include +#include #endif namespace diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.cpp b/Source/Engine/Graphics/Models/SkinnedMesh.cpp index f33b8b4fd..a47ef2302 100644 --- a/Source/Engine/Graphics/Models/SkinnedMesh.cpp +++ b/Source/Engine/Graphics/Models/SkinnedMesh.cpp @@ -15,7 +15,7 @@ #include "Engine/Threading/Task.h" #include "Engine/Threading/Threading.h" #if USE_MONO -#include +#include #endif void SkinnedMesh::Init(SkinnedModel* model, int32 lodIndex, int32 index, int32 materialSlotIndex, const BoundingBox& box, const BoundingSphere& sphere) diff --git a/Source/Engine/Level/Actors/Spline.cpp b/Source/Engine/Level/Actors/Spline.cpp index 63ba0fe4e..52861c210 100644 --- a/Source/Engine/Level/Actors/Spline.cpp +++ b/Source/Engine/Level/Actors/Spline.cpp @@ -5,7 +5,7 @@ #include "Engine/Animations/CurveSerialization.h" #include "Engine/Core/Math/Matrix.h" #if USE_MONO -#include +#include #endif Spline::Spline(const SpawnParams& params) diff --git a/Source/Engine/Localization/CultureInfo.cpp b/Source/Engine/Localization/CultureInfo.cpp index 6afd85737..77de59ee0 100644 --- a/Source/Engine/Localization/CultureInfo.cpp +++ b/Source/Engine/Localization/CultureInfo.cpp @@ -5,9 +5,9 @@ #include "Engine/Scripting/ManagedCLR/MType.h" #include "Engine/Utilities/StringConverter.h" #if USE_MONO -#include -#include -#include +#include +#include +#include typedef struct { diff --git a/Source/Engine/Platform/Android/AndroidDefines.h b/Source/Engine/Platform/Android/AndroidDefines.h index b94634227..ecb034d30 100644 --- a/Source/Engine/Platform/Android/AndroidDefines.h +++ b/Source/Engine/Platform/Android/AndroidDefines.h @@ -33,4 +33,6 @@ #define PLATFORM_TYPE PlatformType::Android #define PLATFORM_CACHE_LINE_SIZE 64 +#define USE_MONO_AOT_MODE MONO_AOT_MODE_NONE + #endif diff --git a/Source/Engine/Platform/Base/WindowBase.cpp b/Source/Engine/Platform/Base/WindowBase.cpp index 3b60f1121..a9ffc8f25 100644 --- a/Source/Engine/Platform/Base/WindowBase.cpp +++ b/Source/Engine/Platform/Base/WindowBase.cpp @@ -15,7 +15,7 @@ #include "Engine/Scripting/ManagedCLR/MMethod.h" #include "Engine/Scripting/ManagedCLR/MClass.h" #if USE_MONO -#include +#include #endif #if USE_MONO diff --git a/Source/Engine/Scripting/DotNet/CoreCLR.cpp b/Source/Engine/Scripting/DotNet/CoreCLR.cpp index 83fcf25e6..be069e75e 100644 --- a/Source/Engine/Scripting/DotNet/CoreCLR.cpp +++ b/Source/Engine/Scripting/DotNet/CoreCLR.cpp @@ -15,7 +15,12 @@ #include #include #elif DOTNET_HOST_MONO +#include "Engine/Scripting/ManagedCLR/MCore.h" +#include "Engine/Scripting/ManagedCLR/MDomain.h" +#include "Engine/Debug/Exceptions/CLRInnerException.h" #include +#include +#include typedef char char_t; #else #error "Unknown .NET runtime host." @@ -30,6 +35,7 @@ static Dictionary CachedFunctions; static const char_t* NativeInteropTypeName = FLAX_CORECLR_TEXT("FlaxEngine.NativeInterop, FlaxEngine.CSharp"); #if DOTNET_HOST_CORECRL + hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config; hostfxr_initialize_for_dotnet_command_line_fn hostfxr_initialize_for_dotnet_command_line; hostfxr_get_runtime_delegate_fn hostfxr_get_runtime_delegate; @@ -39,11 +45,9 @@ get_function_pointer_fn get_function_pointer; hostfxr_set_error_writer_fn hostfxr_set_error_writer; hostfxr_get_dotnet_environment_info_result_fn hostfxr_get_dotnet_environment_info_result; hostfxr_run_app_fn hostfxr_run_app; -#endif bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath) { -#if DOTNET_HOST_CORECRL const FLAX_CORECLR_STRING& library_path = FLAX_CORECLR_STRING(libraryPath); // Get path to hostfxr library @@ -138,31 +142,227 @@ bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath) hostfxr_close(handle); get_function_pointer = (get_function_pointer_fn)pget_function_pointer; -#elif DOTNET_HOST_MONO - LOG(Fatal, "TODO: init mono hosting runtime"); -#endif - return false; } +void CoreCLR::ShutdownHostfxr() +{ +} + void* CoreCLR::GetStaticMethodPointer(const String& methodName) { void* fun; if (CachedFunctions.TryGet(methodName, fun)) return fun; -#if DOTNET_HOST_CORECRL int rc = get_function_pointer(NativeInteropTypeName, FLAX_CORECLR_STRING(methodName).Get(), UNMANAGEDCALLERSONLY_METHOD, nullptr, nullptr, &fun); if (rc != 0) -#else - int rc = -1; -#endif LOG(Fatal, "Failed to get unmanaged function pointer for method {0}: 0x{1:x}", methodName.Get(), (unsigned int)rc); CachedFunctions.Add(methodName, fun); return fun; } +#elif DOTNET_HOST_MONO + +#ifdef USE_MONO_AOT_MODULE +void* MonoAotModuleHandle = nullptr; +#endif +MonoDomain* MonoDomainHandle = nullptr; + +void OnLogCallback(const char* logDomain, const char* logLevel, const char* message, mono_bool fatal, void* userData) +{ + String currentDomain(logDomain); + String msg(message); + msg.Replace('\n', ' '); + + static const char* monoErrorLevels[] = + { + nullptr, + "error", + "critical", + "warning", + "message", + "info", + "debug" + }; + + uint32 errorLevel = 0; + if (logLevel != nullptr) + { + for (uint32 i = 1; i < 7; i++) + { + if (strcmp(monoErrorLevels[i], logLevel) == 0) + { + errorLevel = i; + break; + } + } + } + + if (currentDomain.IsEmpty()) + { + auto domain = MCore::GetActiveDomain(); + if (domain != nullptr) + { + currentDomain = domain->GetName().Get(); + } + else + { + currentDomain = "null"; + } + } + +#if 0 + // Print C# stack trace (crash may be caused by the managed code) + if (mono_domain_get() && Assemblies::FlaxEngine.Assembly->IsLoaded()) + { + const auto managedStackTrace = DebugLog::GetStackTrace(); + if (managedStackTrace.HasChars()) + { + LOG(Warning, "Managed stack trace:"); + LOG_STR(Warning, managedStackTrace); + } + } +#endif + + if (errorLevel == 0) + { + Log::CLRInnerException(String::Format(TEXT("Message: {0} | Domain: {1}"), msg, currentDomain)).SetLevel(LogType::Error); + } + else if (errorLevel <= 2) + { + Log::CLRInnerException(String::Format(TEXT("Message: {0} | Domain: {1}"), msg, currentDomain)).SetLevel(LogType::Error); + } + else if (errorLevel <= 3) + { + LOG(Warning, "Message: {0} | Domain: {1}", msg, currentDomain); + } + else + { + LOG(Info, "Message: {0} | Domain: {1}", msg, currentDomain); + } +} + +void OnPrintCallback(const char* string, mono_bool isStdout) +{ + LOG_STR(Warning, String(string)); +} + +void OnPrintErrorCallback(const char* string, mono_bool isStdout) +{ + // HACK: ignore this message + if (string && Platform::MemoryCompare(string, "debugger-agent: Unable to listen on ", 36) == 0) + return; + + LOG_STR(Error, String(string)); +} + +bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath) +{ +#if 1 + // Enable detailed Mono logging + Platform::SetEnvironmentVariable(TEXT("MONO_LOG_LEVEL"), TEXT("debug")); + Platform::SetEnvironmentVariable(TEXT("MONO_LOG_MASK"), TEXT("all")); + //Platform::SetEnvironmentVariable(TEXT("MONO_GC_DEBUG"), TEXT("6:gc-log.txt,check-remset-consistency,nursery-canaries")); +#endif + +#if defined(USE_MONO_AOT_MODE) + // Enable AOT mode (per-platform) + mono_jit_set_aot_mode(USE_MONO_AOT_MODE); +#endif + +#ifdef USE_MONO_AOT_MODULE + // Load AOT module + const DateTime aotModuleLoadStartTime = DateTime::Now(); + LOG(Info, "Loading Mono AOT module..."); + void* libAotModule = Platform::LoadLibrary(TEXT(USE_MONO_AOT_MODULE)); + if (libAotModule == nullptr) + { + LOG(Error, "Failed to laod Mono AOT module (" TEXT(USE_MONO_AOT_MODULE) ")"); + return true; + } + MonoAotModuleHandle = libAotModule; + void* getModulesPtr = Platform::GetProcAddress(libAotModule, "GetMonoModules"); + if (getModulesPtr == nullptr) + { + LOG(Error, "Failed to get Mono AOT modules getter."); + return true; + } + typedef int (*GetMonoModulesFunc)(void** buffer, int bufferSize); + const auto getModules = (GetMonoModulesFunc)getModulesPtr; + const int32 moduelsCount = getModules(nullptr, 0); + void** modules = (void**)Allocator::Allocate(moduelsCount * sizeof(void*)); + getModules(modules, moduelsCount); + for (int32 i = 0; i < moduelsCount; i++) + { + mono_aot_register_module((void**)modules[i]); + } + Allocator::Free(modules); + LOG(Info, "Mono AOT module loaded in {0}ms", (int32)(DateTime::Now() - aotModuleLoadStartTime).GetTotalMilliseconds()); +#endif + + // TODO: setup C# debugger + + // Connect to mono engine callback system + mono_trace_set_log_handler(OnLogCallback, nullptr); + mono_trace_set_print_handler(OnPrintCallback); + mono_trace_set_printerr_handler(OnPrintErrorCallback); + + // Initialize Mono VM + StringAnsi baseDirectory(Globals::ProjectFolder); + const char* appctxKeys[] = + { + "RUNTIME_IDENTIFIER", + "APP_CONTEXT_BASE_DIRECTORY", + }; + const char* appctxValues[] = + { + MACRO_TO_STR(DOTNET_HOST_RUNTIME_IDENTIFIER), + baseDirectory.Get(), + }; + static_assert(ARRAY_COUNT(appctxKeys) == ARRAY_COUNT(appctxValues), "Invalid appctx setup"); + monovm_initialize(ARRAY_COUNT(appctxKeys), appctxKeys, appctxValues); + + // Init managed runtime +#if PLATFORM_ANDROID || PLATFORM_IOS + const char* monoVersion = "mobile"; +#else + const char* monoVersion = ""; // ignored +#endif + MonoDomainHandle = mono_jit_init_version("Flax", monoVersion); + if (!MonoDomainHandle) + { + LOG(Fatal, "Failed to initialize Mono."); + return true; + } + + // Log info + char* buildInfo = mono_get_runtime_build_info(); + LOG(Info, "Mono runtime version: {0}", String(buildInfo)); + mono_free(buildInfo); + + return false; +} + +void CoreCLR::ShutdownHostfxr() +{ + mono_jit_cleanup(MonoDomainHandle); + MonoDomainHandle = nullptr; + +#ifdef USE_MONO_AOT_MODULE + Platform::FreeLibrary(MonoAotModuleHandle); +#endif +} + +void* CoreCLR::GetStaticMethodPointer(const String& methodName) +{ + MISSING_CODE("TODO: CoreCLR::GetStaticMethodPointer for Mono host runtime"); + return nullptr; +} + +#endif + void CoreCLR::RegisterNativeLibrary(const char* moduleName, const char* modulePath) { static void* RegisterNativeLibraryPtr = CoreCLR::GetStaticMethodPointer(TEXT("RegisterNativeLibrary")); diff --git a/Source/Engine/Scripting/DotNet/CoreCLR.h b/Source/Engine/Scripting/DotNet/CoreCLR.h index 97343e7bd..b1cc01ab5 100644 --- a/Source/Engine/Scripting/DotNet/CoreCLR.h +++ b/Source/Engine/Scripting/DotNet/CoreCLR.h @@ -25,6 +25,7 @@ class CoreCLR { public: static bool InitHostfxr(const String& configPath, const String& libraryPath); + static void ShutdownHostfxr(); /// /// Returns the function pointer to the managed static method in NativeInterop class. diff --git a/Source/Engine/Scripting/DotNet/MonoApi.cpp b/Source/Engine/Scripting/DotNet/MonoApi.cpp index ddb62ebaa..974cb3de0 100644 --- a/Source/Engine/Scripting/DotNet/MonoApi.cpp +++ b/Source/Engine/Scripting/DotNet/MonoApi.cpp @@ -6,8 +6,8 @@ #include "Engine/Core/Collections/Dictionary.h" #include "Engine/Graphics/RenderView.h" #include "Engine/Core/Types/StringBuilder.h" -#include -#include +#include +#include #pragma warning(disable : 4297) diff --git a/Source/Engine/Scripting/InternalCalls/ManagedBitArray.h b/Source/Engine/Scripting/InternalCalls/ManagedBitArray.h index de6a4cff7..79818a9c3 100644 --- a/Source/Engine/Scripting/InternalCalls/ManagedBitArray.h +++ b/Source/Engine/Scripting/InternalCalls/ManagedBitArray.h @@ -9,9 +9,9 @@ #include "Engine/Scripting/ManagedCLR/MField.h" #include "Engine/Scripting/BinaryModule.h" #if USE_MONO -#include -#include -#include +#include +#include +#include struct ManagedBitArray { diff --git a/Source/Engine/Scripting/InternalCalls/ManagedDictionary.h b/Source/Engine/Scripting/InternalCalls/ManagedDictionary.h index d62bd386c..f7535872c 100644 --- a/Source/Engine/Scripting/InternalCalls/ManagedDictionary.h +++ b/Source/Engine/Scripting/InternalCalls/ManagedDictionary.h @@ -12,7 +12,7 @@ #include "Engine/Scripting/ManagedCLR/MAssembly.h" #include "Engine/Scripting/MException.h" #if USE_MONO -#include +#include /// /// Utility interop between C++ and C# for Dictionary collection. diff --git a/Source/Engine/Scripting/MException.cpp b/Source/Engine/Scripting/MException.cpp index 5b65b7125..2cdc4d55f 100644 --- a/Source/Engine/Scripting/MException.cpp +++ b/Source/Engine/Scripting/MException.cpp @@ -3,7 +3,7 @@ #include "MException.h" #include "ManagedCLR/MUtils.h" #if USE_MONO -#include +#include #endif MException::MException(MObject* exception) diff --git a/Source/Engine/Scripting/ManagedCLR/MAssembly.cpp b/Source/Engine/Scripting/ManagedCLR/MAssembly.cpp index b714ed349..87bef8895 100644 --- a/Source/Engine/Scripting/ManagedCLR/MAssembly.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MAssembly.cpp @@ -17,9 +17,9 @@ #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Threading/Threading.h" #if USE_MONO -#include -#include -#include +#include +#include +#include #endif MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name, const MAssemblyOptions& options) diff --git a/Source/Engine/Scripting/ManagedCLR/MClass.cpp b/Source/Engine/Scripting/ManagedCLR/MClass.cpp index ea944447f..809bd1b1f 100644 --- a/Source/Engine/Scripting/ManagedCLR/MClass.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MClass.cpp @@ -10,8 +10,8 @@ #include "Engine/Scripting/Scripting.h" #include "Engine/Core/Log.h" #if USE_MONO -#include -#include +#include +#include #define GET_CUSTOM_ATTR() (MonoCustomAttrInfo*)(_attrInfo ? _attrInfo : _attrInfo = mono_custom_attrs_from_class(_monoClass)) #endif #if USE_NETCORE diff --git a/Source/Engine/Scripting/ManagedCLR/MCore.cpp b/Source/Engine/Scripting/ManagedCLR/MCore.cpp index 09be5da67..b052bde63 100644 --- a/Source/Engine/Scripting/ManagedCLR/MCore.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MCore.cpp @@ -20,19 +20,19 @@ #ifdef USE_MONO_AOT_MODULE #include "Engine/Core/Types/TimeSpan.h" #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #if !USE_MONO_DYNAMIC_LIB -#include +#include #endif #endif @@ -159,6 +159,7 @@ void MCore::UnloadEngine() CoreCLR::CallStaticMethodByName(TEXT("Exit")); MDomains.ClearDelete(); MRootDomain = nullptr; + CoreCLR::ShutdownHostfxr(); } #elif USE_MONO diff --git a/Source/Engine/Scripting/ManagedCLR/MDomain.cpp b/Source/Engine/Scripting/ManagedCLR/MDomain.cpp index 19bfaa158..a0a92dd60 100644 --- a/Source/Engine/Scripting/ManagedCLR/MDomain.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MDomain.cpp @@ -8,7 +8,7 @@ #include "Engine/Debug/Exceptions/ArgumentException.h" #include "Engine/Debug/Exceptions/Exceptions.h" #if USE_MONO -#include +#include #endif extern MDomain* MActiveDomain; diff --git a/Source/Engine/Scripting/ManagedCLR/MEvent.cpp b/Source/Engine/Scripting/ManagedCLR/MEvent.cpp index 8dce9a863..727f64402 100644 --- a/Source/Engine/Scripting/ManagedCLR/MEvent.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MEvent.cpp @@ -4,7 +4,7 @@ #include "MType.h" #include "MClass.h" #if USE_MONO -#include +#include MEvent::MEvent(MonoEvent* monoEvent, const char* name, MClass* parentClass) : _monoEvent(monoEvent) @@ -137,7 +137,7 @@ const Array& MEvent::GetAttributes() const auto length = (uint32)mono_array_length(monoAttributesArray); _attributes.Resize(length); for (uint32 i = 0; i < length; i++) - _attributes[i] = mono_array_get(monoAttributesArray, MonoObject *, i); + _attributes[i] = mono_array_get(monoAttributesArray, MonoObject*, i); mono_custom_attrs_free(attrInfo); #endif return _attributes; diff --git a/Source/Engine/Scripting/ManagedCLR/MField.cpp b/Source/Engine/Scripting/ManagedCLR/MField.cpp index 0d5ba9fc9..400d19c56 100644 --- a/Source/Engine/Scripting/ManagedCLR/MField.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MField.cpp @@ -4,8 +4,8 @@ #include "MType.h" #include "MClass.h" #if USE_MONO -#include -#include +#include +#include MField::MField(MonoClassField* monoField, const char* name, MClass* parentClass) : _monoField(monoField) diff --git a/Source/Engine/Scripting/ManagedCLR/MMethod.cpp b/Source/Engine/Scripting/ManagedCLR/MMethod.cpp index e89c100bd..ad6353284 100644 --- a/Source/Engine/Scripting/ManagedCLR/MMethod.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MMethod.cpp @@ -5,8 +5,8 @@ #include "MClass.h" #include "Engine/Profiler/ProfilerCPU.h" #if USE_MONO -#include -#include +#include +#include MMethod::MMethod(MonoMethod* monoMethod, MClass* parentClass) : MMethod(monoMethod, mono_method_get_name(monoMethod), parentClass) diff --git a/Source/Engine/Scripting/ManagedCLR/MProperty.cpp b/Source/Engine/Scripting/ManagedCLR/MProperty.cpp index f87bae3ab..5166ba4e0 100644 --- a/Source/Engine/Scripting/ManagedCLR/MProperty.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MProperty.cpp @@ -6,7 +6,7 @@ #include "MClass.h" #include "MType.h" #if USE_MONO -#include +#include MProperty::MProperty(MonoProperty* monoProperty, const char* name, MClass* parentClass) : _monoProperty(monoProperty) diff --git a/Source/Engine/Scripting/ManagedCLR/MStaticConverter.h b/Source/Engine/Scripting/ManagedCLR/MStaticConverter.h index 3bf373fab..3c5f248e1 100644 --- a/Source/Engine/Scripting/ManagedCLR/MStaticConverter.h +++ b/Source/Engine/Scripting/ManagedCLR/MStaticConverter.h @@ -4,7 +4,7 @@ #include "Engine/Core/Types/String.h" #if USE_MONO -#include +#include #endif /// diff --git a/Source/Engine/Scripting/ManagedCLR/MType.cpp b/Source/Engine/Scripting/ManagedCLR/MType.cpp index f7c9faed0..dfbc30a4c 100644 --- a/Source/Engine/Scripting/ManagedCLR/MType.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MType.cpp @@ -3,7 +3,7 @@ #include "MType.h" #include "MUtils.h" #if USE_MONO -#include +#include String MType::ToString() const { diff --git a/Source/Engine/Scripting/ManagedCLR/MUtils.h b/Source/Engine/Scripting/ManagedCLR/MUtils.h index 7df25bc85..9dbb80a00 100644 --- a/Source/Engine/Scripting/ManagedCLR/MUtils.h +++ b/Source/Engine/Scripting/ManagedCLR/MUtils.h @@ -11,8 +11,8 @@ #if USE_MONO -#include -#include +#include +#include #if USE_NETCORE #include "Engine/Scripting/DotNet/CoreCLR.h" diff --git a/Source/Engine/Scripting/ManagedSerialization.cpp b/Source/Engine/Scripting/ManagedSerialization.cpp index 737c0c91c..3ff1f5bb9 100644 --- a/Source/Engine/Scripting/ManagedSerialization.cpp +++ b/Source/Engine/Scripting/ManagedSerialization.cpp @@ -8,7 +8,7 @@ #include "StdTypesContainer.h" #include "MException.h" #include "ManagedCLR/MMethod.h" -#include +#include void ManagedSerialization::Serialize(ISerializable::SerializeStream& stream, MObject* object) { diff --git a/Source/Engine/Scripting/Scripting.Internal.cpp b/Source/Engine/Scripting/Scripting.Internal.cpp index e940271ca..02e2c0835 100644 --- a/Source/Engine/Scripting/Scripting.Internal.cpp +++ b/Source/Engine/Scripting/Scripting.Internal.cpp @@ -15,7 +15,7 @@ #include "Engine/Core/Types/Pair.h" #include "Engine/Threading/Threading.h" #if USE_MONO -#include +#include #endif #if USE_MONO diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index 553cb6f88..3741d5e6d 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -31,8 +31,8 @@ #include "Engine/Graphics/RenderTask.h" #include "Engine/Serialization/JsonTools.h" #if USE_MONO -#include -#include +#include +#include #endif #if USE_NETCORE #include "DotNet/CoreCLR.h" diff --git a/Source/Engine/Scripting/ScriptingObject.cpp b/Source/Engine/Scripting/ScriptingObject.cpp index 61717b8ef..bfe4b36c3 100644 --- a/Source/Engine/Scripting/ScriptingObject.cpp +++ b/Source/Engine/Scripting/ScriptingObject.cpp @@ -17,8 +17,8 @@ #include "ManagedCLR/MCore.h" #include "FlaxEngine.Gen.h" #if USE_MONO -#include -#include +#include +#include #endif #define ScriptingObject_unmanagedPtr "__unmanagedPtr" diff --git a/Source/Engine/Serialization/Serialization.cpp b/Source/Engine/Serialization/Serialization.cpp index a913781a9..2e0442408 100644 --- a/Source/Engine/Serialization/Serialization.cpp +++ b/Source/Engine/Serialization/Serialization.cpp @@ -24,7 +24,7 @@ #include "Engine/Content/Asset.h" #include "Engine/Utilities/Encryption.h" #if USE_MONO -#include +#include #endif void ISerializable::DeserializeIfExists(DeserializeStream& stream, const char* memberName, ISerializeModifier* modifier) diff --git a/Source/Engine/Threading/JobSystem.cpp b/Source/Engine/Threading/JobSystem.cpp index 396294e56..f6df609ae 100644 --- a/Source/Engine/Threading/JobSystem.cpp +++ b/Source/Engine/Threading/JobSystem.cpp @@ -11,8 +11,8 @@ #include "Engine/Scripting/ManagedCLR/MCore.h" #if USE_MONO #include "Engine/Scripting/ManagedCLR/MDomain.h" -#include -#include +#include +#include #endif // Jobs storage perf info: diff --git a/Source/Engine/UI/UICanvas.cpp b/Source/Engine/UI/UICanvas.cpp index 22d7ea550..b6e4d5497 100644 --- a/Source/Engine/UI/UICanvas.cpp +++ b/Source/Engine/UI/UICanvas.cpp @@ -6,7 +6,7 @@ #include "Engine/Scripting/ManagedCLR/MClass.h" #include "Engine/Serialization/Serialization.h" #if USE_MONO -#include +#include #endif #if COMPILE_WITHOUT_CSHARP diff --git a/Source/Engine/UI/UIControl.cpp b/Source/Engine/UI/UIControl.cpp index 75d25aed7..5eecfafb1 100644 --- a/Source/Engine/UI/UIControl.cpp +++ b/Source/Engine/UI/UIControl.cpp @@ -7,7 +7,7 @@ #include "Engine/Scripting/Scripting.h" #include "Engine/Serialization/Serialization.h" #if USE_MONO -#include +#include #endif #if COMPILE_WITHOUT_CSHARP diff --git a/Source/ThirdParty/mono-2.0/mono.Build.cs b/Source/ThirdParty/mono-2.0/mono.Build.cs index 7d7830081..53accc4e1 100644 --- a/Source/ThirdParty/mono-2.0/mono.Build.cs +++ b/Source/ThirdParty/mono-2.0/mono.Build.cs @@ -97,9 +97,6 @@ public class mono : DepsModule break; default: throw new InvalidPlatformException(options.Platform.Target); } - - // TODO: remove hardcoded include path for all modules and use this public thing to pass include only to modules that use it - //options.PublicIncludePaths.Add(Path.Combine(Globals.EngineRoot, @"Source\ThirdParty\mono-2.0")); } /// diff --git a/Source/ThirdParty/nethost/nethost.Build.cs b/Source/ThirdParty/nethost/nethost.Build.cs index c8d960db7..e9afa6629 100644 --- a/Source/ThirdParty/nethost/nethost.Build.cs +++ b/Source/ThirdParty/nethost/nethost.Build.cs @@ -33,7 +33,7 @@ public class nethost : ThirdPartyModule var dotnetSdk = DotNetSdk.Instance; if (!dotnetSdk.IsValid) throw new Exception($"Missing NET SDK {DotNetSdk.MinimumVersion}."); - if (!dotnetSdk.GetHostRuntime(options.Platform.Target, options.Architecture, out var hostRuntimePath)) + if (!dotnetSdk.GetHostRuntime(options.Platform.Target, options.Architecture, out var hostRuntime)) { if (options.Target.IsPreBuilt) return; // Ignore missing Host Runtime when engine is already prebuilt @@ -43,48 +43,51 @@ public class nethost : ThirdPartyModule } // Setup build configuration - bool useMonoHost = false; switch (options.Platform.Target) { case TargetPlatform.Windows: case TargetPlatform.XboxOne: case TargetPlatform.XboxScarlett: case TargetPlatform.UWP: - options.OutputFiles.Add(Path.Combine(hostRuntimePath, "nethost.lib")); - options.DependencyFiles.Add(Path.Combine(hostRuntimePath, "nethost.dll")); + options.OutputFiles.Add(Path.Combine(hostRuntime.Path, "nethost.lib")); + options.DependencyFiles.Add(Path.Combine(hostRuntime.Path, "nethost.dll")); break; case TargetPlatform.Linux: - options.OutputFiles.Add(Path.Combine(hostRuntimePath, "libnethost.a")); - options.DependencyFiles.Add(Path.Combine(hostRuntimePath, "libnethost.so")); + options.OutputFiles.Add(Path.Combine(hostRuntime.Path, "libnethost.a")); + options.DependencyFiles.Add(Path.Combine(hostRuntime.Path, "libnethost.so")); break; case TargetPlatform.Mac: - options.OutputFiles.Add(Path.Combine(hostRuntimePath, "libnethost.a")); - options.DependencyFiles.Add(Path.Combine(hostRuntimePath, "libnethost.dylib")); + options.OutputFiles.Add(Path.Combine(hostRuntime.Path, "libnethost.a")); + options.DependencyFiles.Add(Path.Combine(hostRuntime.Path, "libnethost.dylib")); break; case TargetPlatform.Switch: case TargetPlatform.PS4: case TargetPlatform.PS5: - options.OutputFiles.Add(Path.Combine(hostRuntimePath, "libnethost.a")); - //options.OutputFiles.Add(Path.Combine(hostRuntimePath, "libhostfxr.a")); + options.OutputFiles.Add(Path.Combine(hostRuntime.Path, "libnethost.a")); + //options.OutputFiles.Add(Path.Combine(hostRuntime.Path, "libhostfxr.a")); break; - case TargetPlatform.Android: - useMonoHost = true; - break; - default: - throw new InvalidPlatformException(options.Platform.Target); + case TargetPlatform.Android: break; + default: throw new InvalidPlatformException(options.Platform.Target); } options.DependencyFiles.Add(Path.Combine(FolderPath, "FlaxEngine.CSharp.runtimeconfig.json")); - if (useMonoHost) + options.PublicDefinitions.Add("DOTNET_HOST_RUNTIME_IDENTIFIER=" + DotNetSdk.GetHostRuntimeIdentifier(options.Platform.Target, options.Architecture)); + switch (hostRuntime.Type) { - // Use Mono for runtime hosting - options.PublicDefinitions.Add("DOTNET_HOST_MONO"); - options.PublicIncludePaths.Add(Path.Combine(hostRuntimePath, "include", "mono-2.0")); - } - else + case DotNetSdk.HostType.CoreCRL: { // Use CoreCRL for runtime hosting options.PublicDefinitions.Add("DOTNET_HOST_CORECRL"); - options.PublicIncludePaths.Add(hostRuntimePath); + options.PublicIncludePaths.Add(hostRuntime.Path); + break; + } + case DotNetSdk.HostType.Mono: + { + // Use Mono for runtime hosting + options.PublicDefinitions.Add("DOTNET_HOST_MONO"); + //options.PublicIncludePaths.Add(Path.Combine(hostRuntime.Path, "include", "mono-2.0")); already setup in ProjectTarget.SetupTargetEnvironment + break; + } + default: throw new ArgumentOutOfRangeException(); } } } diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs index 342a359e4..7ba6f4e1f 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs @@ -26,7 +26,87 @@ namespace Flax.Build /// public sealed class DotNetSdk : Sdk { - private Dictionary, string> _hostRuntimes = new(); + /// + /// Runtime host types. + /// + public enum HostType + { + /// + /// Core CRL runtime. + /// + CoreCRL, + + /// + /// Old-school Mono runtime. + /// + Mono, + } + + /// + /// Host runtime description. + /// + public struct HostRuntime : IEquatable + { + /// + /// The path to runtime host contents folder for a given target platform and architecture. + /// In format: <RootPath>/packs/Microsoft.NETCore.App.Host.<os>/<VersionName>/runtimes/<os>-<arch>/native + /// + public string Path; + + /// + /// Type of the host. + /// + public HostType Type; + + /// + /// Initializes a new instance of the class. + /// + /// The target platform (used to guess the host type). + /// The host contents folder path. + public HostRuntime(TargetPlatform platform, string path) + { + Path = path; + + // Detect host type (this could check if monosgen-2.0 or hostfxr lib exists but platform-switch is easier) + switch (platform) + { + case TargetPlatform.Windows: + case TargetPlatform.Linux: + case TargetPlatform.Mac: + Type = HostType.CoreCRL; + break; + default: + Type = HostType.Mono; + break; + } + } + + /// + public bool Equals(HostRuntime other) + { + return Path == other.Path && Type == other.Type; + } + + /// + public override bool Equals(object? obj) + { + return obj is HostRuntime other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(Path, (int)Type); + } + + /// + public override string ToString() + { + return Path; + } + } + + private Dictionary, HostRuntime> _hostRuntimes = new(); /// /// The singleton instance. @@ -191,6 +271,65 @@ namespace Flax.Build Log.Verbose($" - Host Runtime for {e.Key.Key} {e.Key.Value}"); } + /// + /// Gets the host runtime identifier for a given platform (eg. linux-arm64). + /// + /// Target platform. + /// Target architecture. + /// Runtime identifier. + public static string GetHostRuntimeIdentifier(TargetPlatform platform, TargetArchitecture architecture) + { + string result; + switch (platform) + { + case TargetPlatform.Windows: + case TargetPlatform.XboxOne: + case TargetPlatform.XboxScarlett: + case TargetPlatform.UWP: + result = "win"; + break; + case TargetPlatform.Linux: + result = "linux"; + break; + case TargetPlatform.PS4: + result = "ps4"; + break; + case TargetPlatform.PS5: + result = "ps5"; + break; + case TargetPlatform.Android: + result = "android"; + break; + case TargetPlatform.Switch: + result = "switch"; + break; + case TargetPlatform.Mac: + result = "osx"; + break; + case TargetPlatform.iOS: + result = "ios"; + break; + default: throw new InvalidPlatformException(platform); + } + switch (architecture) + { + case TargetArchitecture.x86: + result += "-x86"; + break; + case TargetArchitecture.x64: + result += "-x64"; + break; + case TargetArchitecture.ARM: + result += "-arm"; + break; + case TargetArchitecture.ARM64: + result += "-arm64"; + break; + default: throw new InvalidArchitectureException(architecture); + } + return result; + } + /// /// Prints the .NET runtimes hosts. /// @@ -211,12 +350,11 @@ namespace Flax.Build } /// - /// Gets the path to runtime host contents folder for a given target platform and architecture. - /// In format: <RootPath>/packs/Microsoft.NETCore.App.Host.<os>/<VersionName>/runtimes/<os>-<arch>/native + /// Gets the runtime host for a given target platform and architecture. /// - public bool GetHostRuntime(TargetPlatform platform, TargetArchitecture arch, out string path) + public bool GetHostRuntime(TargetPlatform platform, TargetArchitecture arch, out HostRuntime hostRuntime) { - return _hostRuntimes.TryGetValue(new KeyValuePair(platform, arch), out path); + return _hostRuntimes.TryGetValue(new KeyValuePair(platform, arch), out hostRuntime); } /// @@ -228,7 +366,7 @@ namespace Flax.Build public void AddHostRuntime(TargetPlatform platform, TargetArchitecture arch, string path) { if (Directory.Exists(path)) - _hostRuntimes[new KeyValuePair(platform, arch)] = path; + _hostRuntimes[new KeyValuePair(platform, arch)] = new HostRuntime(platform, path); } private bool TryAddHostRuntime(TargetPlatform platform, TargetArchitecture arch, string rid, string runtimeName = null) @@ -254,7 +392,7 @@ namespace Flax.Build exists = Directory.Exists(path); if (exists) - _hostRuntimes[new KeyValuePair(platform, arch)] = path; + _hostRuntimes[new KeyValuePair(platform, arch)] = new HostRuntime(platform, path); return exists; } diff --git a/Source/Tools/Flax.Build/Build/ProjectTarget.cs b/Source/Tools/Flax.Build/Build/ProjectTarget.cs index 98162264b..cc7549cd1 100644 --- a/Source/Tools/Flax.Build/Build/ProjectTarget.cs +++ b/Source/Tools/Flax.Build/Build/ProjectTarget.cs @@ -62,7 +62,20 @@ namespace Flax.Build // Add include paths for this project sources and engine third-party sources var depsRoot = options.DepsFolder; - options.CompileEnv.IncludePaths.Add(Path.Combine(Globals.EngineRoot, @"Source\ThirdParty\mono-2.0")); // TODO: let mono module expose it + { + // TODO: rethink how we should expose mono (and dotnet host api) in general + DotNetSdk.Instance.GetHostRuntime(options.Platform.Target, options.Architecture, out var hostRuntime); + if (hostRuntime.Type == DotNetSdk.HostType.Mono) + { + // Use mono headers from the host runtime + options.CompileEnv.IncludePaths.Add(Path.Combine(hostRuntime.Path, "include", "mono-2.0")); + } + else + { + // Use in-built mono headers + options.CompileEnv.IncludePaths.Add(Path.Combine(Globals.EngineRoot, @"Source\ThirdParty\mono-2.0")); + } + } options.CompileEnv.IncludePaths.Add(Path.Combine(Globals.EngineRoot, @"Source\ThirdParty")); options.LinkEnv.LibraryPaths.Add(depsRoot); diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs b/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs index 75e62a394..0c91a121d 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs @@ -54,7 +54,7 @@ namespace Flax.Deps.Dependencies SetupDirectory(artifacts, true); // Peek options - string os, arch, runtimeFlavor, subset, hostRuntimeName, buildArgsBase = string.Empty; + string os, arch, runtimeFlavor, subset, hostRuntimeName = DotNetSdk.GetHostRuntimeIdentifier(targetPlatform, architecture), buildArgsBase = string.Empty; bool setupVersion = false; string[] hostRuntimeFiles = Array.Empty(); var envVars = new Dictionary(); @@ -80,25 +80,21 @@ namespace Flax.Deps.Dependencies os = "windows"; runtimeFlavor = "CoreCLR"; subset = "clr"; - hostRuntimeName = $"win-{arch}"; break; case TargetPlatform.Linux: os = "Linux"; runtimeFlavor = "CoreCLR"; subset = "clr"; - hostRuntimeName = $"linux-{arch}"; break; case TargetPlatform.Mac: os = "OSX"; runtimeFlavor = "CoreCLR"; subset = "clr"; - hostRuntimeName = $"osx-{arch}"; break; case TargetPlatform.Android: os = "Android"; runtimeFlavor = "Mono"; subset = "mono+libs"; - hostRuntimeName = $"android-{arch}"; break; case TargetPlatform.PS4: os = "PS4"; @@ -106,7 +102,6 @@ namespace Flax.Deps.Dependencies subset = "mono+libs"; setupVersion = true; buildArgsBase = " /p:RuntimeOS=ps4 -cmakeargs \"-DCLR_CROSS_COMPONENTS_BUILD=1\""; - hostRuntimeName = $"ps4-{arch}"; hostRuntimeFiles = new[] { "coreclr_delegates.h",