diff --git a/Source/Editor/Cooker/Platform/Web/WebPlatformTools.cpp b/Source/Editor/Cooker/Platform/Web/WebPlatformTools.cpp
index dfb0b5403..db822bec2 100644
--- a/Source/Editor/Cooker/Platform/Web/WebPlatformTools.cpp
+++ b/Source/Editor/Cooker/Platform/Web/WebPlatformTools.cpp
@@ -38,7 +38,7 @@ ArchitectureType WebPlatformTools::GetArchitecture() const
DotNetAOTModes WebPlatformTools::UseAOT() const
{
- return DotNetAOTModes::NoDotnet;
+ return DotNetAOTModes::None;//DotNetAOTModes::MonoAOTStatic;//DotNetAOTModes::NoDotnet;
}
PixelFormat WebPlatformTools::GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format)
diff --git a/Source/Engine/Graphics/Graphics.Build.cs b/Source/Engine/Graphics/Graphics.Build.cs
index 015e2c01d..ec054528b 100644
--- a/Source/Engine/Graphics/Graphics.Build.cs
+++ b/Source/Engine/Graphics/Graphics.Build.cs
@@ -97,7 +97,8 @@ public class Graphics : EngineModule
Log.WarningOnce(string.Format("Building for {0} without Vulkan rendering backend (Vulkan SDK is missing)", options.Platform.Target), ref _logMissingVulkanSDK);
break;
case TargetPlatform.Web:
- options.PrivateDependencies.Add("GraphicsDeviceWebGPU");
+ options.PrivateDependencies.Add("GraphicsDeviceNull");
+ //options.PrivateDependencies.Add("GraphicsDeviceWebGPU");
break;
default: throw new InvalidPlatformException(options.Platform.Target);
}
diff --git a/Source/Engine/Physics/CollisionData.cs b/Source/Engine/Physics/CollisionData.cs
index 8bb9260d1..278a99e0c 100644
--- a/Source/Engine/Physics/CollisionData.cs
+++ b/Source/Engine/Physics/CollisionData.cs
@@ -6,6 +6,7 @@ namespace FlaxEngine
{
partial class CollisionData
{
+#if false
///
/// Cooks the mesh collision data and updates the virtual asset. action cannot be performed on a main thread.
/// [Deprecated on 16.06.2022, expires on 16.06.2024]
@@ -68,5 +69,6 @@ namespace FlaxEngine
for (int i = 0; i < tmp.Length; i++)
vertexBuffer[i] = tmp[i];
}
+#endif
}
}
diff --git a/Source/Engine/Platform/Web/WebDefines.h b/Source/Engine/Platform/Web/WebDefines.h
index d5511d1f7..9db34135a 100644
--- a/Source/Engine/Platform/Web/WebDefines.h
+++ b/Source/Engine/Platform/Web/WebDefines.h
@@ -29,4 +29,8 @@
#define GPU_ENABLE_ASYNC_RESOURCES_CREATION 0
#endif
+// Use AOT for Mono
+#define USE_MONO_AOT 1
+#define USE_MONO_AOT_MODE MONO_AOT_MODE_FULL
+
#endif
diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp
index 4be0ce1a1..e9badc989 100644
--- a/Source/Engine/Scripting/Runtime/DotNet.cpp
+++ b/Source/Engine/Scripting/Runtime/DotNet.cpp
@@ -51,7 +51,7 @@
#include
#include
typedef char char_t;
-#define DOTNET_HOST_MONO_DEBUG 0
+#define DOTNET_HOST_MONO_DEBUG 1
#ifdef USE_MONO_AOT_MODULE
void* MonoAotModuleHandle = nullptr;
#endif
@@ -270,6 +270,36 @@ struct NativePropertyDefinitions
MMethodAttributes setterAttributes;
};
+#if PLATFORM_WEB
+
+extern "C"
+{
+ DLLEXPORT void schedule_background_exec()
+ {
+ }
+
+ DLLEXPORT int mono_wasm_process_current_pid()
+ {
+ return -1;
+ }
+
+ DLLEXPORT void mono_wasm_schedule_timer(int shortestDueTimeMs)
+ {
+ }
+
+ DLLEXPORT int mono_jiterp_parse_option(const char* option)
+ {
+ return -1;
+ }
+
+ DLLEXPORT int mono_wasm_browser_entropy(uint8_t* buffer, int32_t bufferLength)
+ {
+ return 0;
+ }
+}
+
+#endif
+
MDomain* MCore::CreateDomain(const StringAnsi& domainName)
{
return nullptr;
@@ -281,6 +311,7 @@ void MCore::UnloadDomain(const StringAnsi& domainName)
bool MCore::LoadEngine()
{
+ LOG(Info, "DotNet MCore::LoadEngine");
PROFILE_CPU();
PROFILE_MEM(ScriptingCSharp);
@@ -1757,6 +1788,7 @@ hostfxr_run_app_fn hostfxr_run_app;
bool InitHostfxr()
{
+ LOG(Info, "InitHostfxr");
const ::String csharpLibraryPath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.dll");
const ::String csharpRuntimeConfigPath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.runtimeconfig.json");
if (!FileSystem::FileExists(csharpLibraryPath))
@@ -2187,6 +2219,7 @@ bool MonoAotPreloadTask::Run()
bool InitHostfxr()
{
+ LOG(Info, "InitHostfxr2");
#if DOTNET_HOST_MONO_DEBUG
// Enable detailed Mono logging
Platform::SetEnvironmentVariable(TEXT("MONO_LOG_LEVEL"), TEXT("debug"));
@@ -2205,6 +2238,7 @@ bool InitHostfxr()
#if defined(USE_MONO_AOT_MODE)
// Enable AOT mode (per-platform)
+ LOG(Info, "InitHostfxr mono_jit_set_aot_mode");
mono_jit_set_aot_mode(USE_MONO_AOT_MODE);
#endif
@@ -2215,6 +2249,7 @@ bool InitHostfxr()
#endif
#ifdef USE_MONO_AOT_MODULE
+ LOG(Info, "InitHostfxr USE_MONO_AOT_MODULE");
// Wait for AOT module preloading
while (Platform::AtomicRead(&MonoAotPreloadServiceInstance.Ready) == 0)
Platform::Yield();
@@ -2246,6 +2281,7 @@ bool InitHostfxr()
#endif
// Setup debugger
+ LOG(Info, "InitHostfxr2 setup debugger");
{
int32 debuggerLogLevel = 0;
if (CommandLine::Options.MonoLog.IsTrue() || DOTNET_HOST_MONO_DEBUG)
@@ -2292,6 +2328,7 @@ bool InitHostfxr()
#endif
}
+ LOG(Info, "InitHostfxr2 set log handler");
// Connect to mono engine callback system
mono_trace_set_log_handler(OnLogCallback, nullptr);
mono_trace_set_print_handler(OnPrintCallback);
@@ -2325,15 +2362,18 @@ bool InitHostfxr()
#else
const char* monoVersion = ""; // ignored
#endif
+ LOG(Info, "InitHostfxr2 mono_jit_init_version");
MonoDomainHandle = mono_jit_init_version("Flax", monoVersion);
if (!MonoDomainHandle)
{
LOG(Fatal, "Failed to initialize Mono.");
return true;
}
+ LOG(Info, "InitHostfxr2 mono_gc_init_finalizer_thread");
mono_gc_init_finalizer_thread();
// Log info
+ LOG(Info, "InitHostfxr2 mono_get_runtime_build_info");
char* buildInfo = mono_get_runtime_build_info();
LOG(Info, "Mono runtime version: {0}", String(buildInfo));
mono_free(buildInfo);
diff --git a/Source/Engine/Scripting/Runtime/Mono.cpp b/Source/Engine/Scripting/Runtime/Mono.cpp
index 06392f932..a7b3d4e36 100644
--- a/Source/Engine/Scripting/Runtime/Mono.cpp
+++ b/Source/Engine/Scripting/Runtime/Mono.cpp
@@ -464,6 +464,7 @@ static void* OnMonoLinuxDlSym(void* handle, const char* name, char** err, void*
bool MCore::LoadEngine()
{
+ LOG(Info, "Mono MCore::LoadEngine");
PROFILE_CPU();
ASSERT(Globals::MonoPath.IsANSI());
diff --git a/Source/Engine/Scripting/Runtime/None.cpp b/Source/Engine/Scripting/Runtime/None.cpp
index 1ddaeae8e..d1e9d6c56 100644
--- a/Source/Engine/Scripting/Runtime/None.cpp
+++ b/Source/Engine/Scripting/Runtime/None.cpp
@@ -47,6 +47,7 @@ void MCore::UnloadDomain(const StringAnsi& domainName)
bool MCore::LoadEngine()
{
+ LOG(Info, "None MCore::LoadEngine");
MRootDomain = New("Root");
MDomains.Add(MRootDomain);
return false;
diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp
index 9b8439528..b60defd4a 100644
--- a/Source/Engine/Scripting/Scripting.cpp
+++ b/Source/Engine/Scripting/Scripting.cpp
@@ -176,16 +176,19 @@ void onEngineUnloading(MAssembly* assembly);
bool ScriptingService::Init()
{
+ LOG(Info, "ScriptingService::Init");
PROFILE_MEM(Scripting);
Stopwatch stopwatch;
// Initialize managed runtime
+ LOG(Info, "ScriptingService::Init MCore::LoadEngine");
if (MCore::LoadEngine())
{
LOG(Fatal, "C# runtime initialization failed.");
return true;
}
+ LOG(Info, "ScriptingService::Init MCore::CreateScriptingAssemblyLoadContext");
MCore::CreateScriptingAssemblyLoadContext();
// Cache root domain
diff --git a/Source/ThirdParty/SDL/SDL.Build.cs b/Source/ThirdParty/SDL/SDL.Build.cs
index a810555bb..ea5f5c373 100644
--- a/Source/ThirdParty/SDL/SDL.Build.cs
+++ b/Source/ThirdParty/SDL/SDL.Build.cs
@@ -49,7 +49,8 @@ public class SDL : DepsModule
options.OutputFiles.Add(Path.Combine(depsRoot, "libSDL3.a"));
break;
case TargetPlatform.Web:
- options.OutputFiles.Add("--use-port=sdl3");
+ //options.OutputFiles.Add("--use-port=sdl3");
+ options.OutputFiles.Add(Path.Combine(depsRoot, "libSDL3.a"));
break;
default: throw new InvalidPlatformException(options.Platform.Target);
}
diff --git a/Source/ThirdParty/nethost/nethost.Build.cs b/Source/ThirdParty/nethost/nethost.Build.cs
index 2910e401d..e9ac30756 100644
--- a/Source/ThirdParty/nethost/nethost.Build.cs
+++ b/Source/ThirdParty/nethost/nethost.Build.cs
@@ -104,6 +104,47 @@ public class nethost : ThirdPartyModule
options.PublicDefinitions.Add("USE_MONO_DYNAMIC_LIB");
options.DependencyFiles.Add(Path.Combine(hostRuntime.Path, "libmonosgen-2.0.dylib"));
options.Libraries.Add(Path.Combine(hostRuntime.Path, "libmonosgen-2.0.dylib"));
+ break;
+ case TargetPlatform.Web:
+ //options.PublicDefinitions.Add("USE_MONO_DYNAMIC_LIB");
+ options.DependencyFiles.Add(Path.Combine(hostRuntime.Path, "libmonosgen-2.0.a"));
+ options.Libraries.Add(Path.Combine(hostRuntime.Path, "libmonosgen-2.0.a"));
+
+ foreach (var lib in new string[] {
+ //"libz.a",
+ "libSystem.Native.a",
+ //"libSystem.Globalization.Native.a",
+ //"libSystem.IO.Compression.Native.a",
+ "libmono-component-debugger-stub-static.a",//"libmono-component-debugger-static.a",
+ "libmono-component-hot_reload-stub-static.a",//"libmono-component-hot_reload-static.a",
+ "libmono-component-marshal-ilgen-stub-static.a",//"libmono-component-marshal-ilgen-static.a",
+ "libmono-component-diagnostics_tracing-stub-static.a",
+ //"libmono-profiler-browser.a",
+ "libmono-wasm-eh-js.a",
+ //"libicuuc.a",
+ //"libmono-icall-table.a",
+ /*"libmono-wasm-nosimd.a",
+ "libSystem.Native.a",
+ "libSystem.IO.Compression.Native.a",
+ //"libmono-wasm-eh-wasm.a",
+ //"libmono-ee-interp.a",
+ "libicuuc.a",
+ "libicui18n.a",
+ "libicudata.a",
+ "libbrotlienc.a",
+ "libbrotlidec.a",
+ "libbrotlicommon.a",*/
+ //"dotnet.native.wasm",
+ })
+ {
+ options.DependencyFiles.Add(Path.Combine(hostRuntime.Path, lib));
+ options.Libraries.Add(Path.Combine(hostRuntime.Path, lib));
+ }
+
+ //options.DependencyFiles.Add(Path.Combine(hostRuntime.Path, "dotnet.native.wasm"));
+ //options.LinkEnv.InputFiles.Add(Path.Combine(hostRuntime.Path, "dotnet.native.wasm"));
+ //options.SourceFiles.Add(Path.Combine(hostRuntime.Path, "dotnet.native.js"));
+
break;
default: throw new InvalidPlatformException(options.Platform.Target);
}
diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetAOT.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetAOT.cs
index c9db8fd64..4a1776a69 100644
--- a/Source/Tools/Flax.Build/Build/DotNet/DotNetAOT.cs
+++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetAOT.cs
@@ -24,6 +24,11 @@ namespace Flax.Build
///
ILC,
+ ///
+ ///
+ ///
+ WebCIL,
+
///
/// Use Mono AOT to cross-compile all used C# assemblies into native platform shared libraries.
///
@@ -61,7 +66,7 @@ namespace Flax.Build
public static void RunDotNetAOT()
{
Log.Info("Running .NET AOT in mode " + AOTMode);
- //Configuration.CustomDefines.Add("DOTNET_AOT_DEBUG");
+ Configuration.CustomDefines.Add("DOTNET_AOT_DEBUG");
DotNetAOT.RunAOT();
}
@@ -318,6 +323,8 @@ namespace Flax.Build
var dotnetLibPath = Utilities.NormalizePath(Path.GetDirectoryName(coreLibPaths[0]));
Log.Info("Class library found in: " + dotnetLibPath);
+ bool wasm = true;
+
// Build list of assemblies to process (use game assemblies as root to walk over used references from stdlib)
var assembliesPaths = new List();
if (Configuration.SkipUnusedDotnetLibsPackaging)
@@ -354,6 +361,16 @@ namespace Flax.Build
assembliesPaths.AddRange(stdLibFiles);
assembliesPaths.AddRange(inputFiles);
}
+ if (!wasm)
+ {
+ List assembliesPaths2 = new();
+ foreach (var assemblyPath in assembliesPaths)
+ {
+ if (!assemblyPath.StartsWith(dotnetLibPath))
+ assembliesPaths2.Add(assemblyPath);
+ }
+ assembliesPaths = assembliesPaths2;
+ }
// Run compilation
bool failed = false, validCache = true, coreLibDirty = false;
@@ -370,6 +387,7 @@ namespace Flax.Build
buildToolchain.CompileCSharp(ref options);
platformToolsPath = options.PlatformToolsPath;
}
+ if (!wasm)
{
// Check if core library has been modified
var options = new Toolchain.CSharpOptions
@@ -411,6 +429,13 @@ namespace Flax.Build
EnableDebugSymbols = useDebug,
EnableToolDebug = dotnetAotDebug,
};
+
+ if (true)
+ {
+ //if (Path.GetFileNameWithoutExtension(assemblyPath) == "System.Private.CoreLib")
+
+ }
+
buildToolchain.CompileCSharp(ref options);
// Skip if output is already generated and is newer than a source assembly
@@ -470,7 +495,9 @@ namespace Flax.Build
Utilities.FileCopy(assemblyPath, Path.Combine(dotnetOutputPath, assemblyFileName), Utilities.CopyMode.OverrideIfNewer);
}
};
- if (Configuration.MaxConcurrency > 1 && Configuration.ConcurrencyProcessorScale > 0.0f && !dotnetAotDebug)
+ Log.Info("AOT: " + string.Join(", ", assembliesPaths));
+ Log.Info("");
+ if (false && Configuration.MaxConcurrency > 1 && Configuration.ConcurrencyProcessorScale > 0.0f && !dotnetAotDebug)
{
// Multi-threaded
System.Threading.Tasks.Parallel.ForEach(assembliesPaths, compileAssembly);
@@ -479,7 +506,14 @@ namespace Flax.Build
{
// Single-threaded
foreach (var assemblyPath in assembliesPaths)
+ {
+ Log.Info("");
+ Log.Warning(" " + assemblyPath);
+ Log.Info("");
compileAssembly(assemblyPath);
+ if (failed)
+ break;
+ }
}
if (failed)
throw new Exception($"Failed to run AOT. See log ({Configuration.LogFile}).");
diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs
index de0fa755c..4c3309d37 100644
--- a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs
+++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs
@@ -148,6 +148,7 @@ namespace Flax.Build
TargetPlatform.Windows,
TargetPlatform.Linux,
TargetPlatform.Mac,
+ TargetPlatform.Web,
};
}
}
@@ -356,6 +357,9 @@ namespace Flax.Build
TryAddHostRuntime(TargetPlatform.Android, TargetArchitecture.ARM64, "android-arm64", "Runtime.Mono");
TryAddHostRuntime(TargetPlatform.iOS, TargetArchitecture.ARM, "ios-arm64", "Runtime.Mono");
TryAddHostRuntime(TargetPlatform.iOS, TargetArchitecture.ARM64, "ios-arm64", "Runtime.Mono");
+ TryAddHostRuntime(TargetPlatform.Web, TargetArchitecture.x86, "browser-wasm", "Runtime.Mono");
+ //TryAddHostRuntime(TargetPlatform.Web, TargetArchitecture.x86, "browser-wasm", "Runtime.Mono.multithread");
+ //TryAddHostRuntime(TargetPlatform.Web, TargetArchitecture.x86, "browser-wasm", "Runtime.AOT.win-x64.Cross");
// Found
IsValid = true;
@@ -410,10 +414,16 @@ namespace Flax.Build
case TargetPlatform.iOS:
result = "ios";
break;
+ case TargetPlatform.Web:
+ result = "browser";
+ break;
default: throw new InvalidPlatformException(platform);
}
switch (architecture)
{
+ case TargetArchitecture.x86 when platform == TargetPlatform.Web:
+ result += "-wasm";
+ break;
case TargetArchitecture.x86:
result += "-x86";
break;
diff --git a/Source/Tools/Flax.Build/Build/Target.cs b/Source/Tools/Flax.Build/Build/Target.cs
index 257cff587..afd2f353d 100644
--- a/Source/Tools/Flax.Build/Build/Target.cs
+++ b/Source/Tools/Flax.Build/Build/Target.cs
@@ -276,6 +276,7 @@ namespace Flax.Build
case TargetPlatform.Linux:
case TargetPlatform.iOS:
case TargetPlatform.Mac:
+ case TargetPlatform.Web:
// TODO: try to disable this on more platforms! (eg. LocalizationService::OnLocalizationChanged uses it)
options.CompileEnv.EnableExceptions = true;
break;
diff --git a/Source/Tools/Flax.Build/Configuration.cs b/Source/Tools/Flax.Build/Configuration.cs
index 9f2796767..269b8e047 100644
--- a/Source/Tools/Flax.Build/Configuration.cs
+++ b/Source/Tools/Flax.Build/Configuration.cs
@@ -296,8 +296,8 @@ namespace Flax.Build
public static bool WithCSharp(NativeCpp.BuildOptions options)
{
- if (options.Platform.Target == TargetPlatform.Web)
- return false; // TODO: implement .NET for WebAssembly
+ //if (options.Platform.Target == TargetPlatform.Web)
+ // return false; // TODO: implement .NET for WebAssembly
return UseCSharp || options.Target.IsEditor;
}
diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/SDL.cs b/Source/Tools/Flax.Build/Deps/Dependencies/SDL.cs
index 830b43500..ff7d34cca 100644
--- a/Source/Tools/Flax.Build/Deps/Dependencies/SDL.cs
+++ b/Source/Tools/Flax.Build/Deps/Dependencies/SDL.cs
@@ -123,6 +123,7 @@ namespace Flax.Deps.Dependencies
}
case TargetPlatform.Linux:
case TargetPlatform.Mac:
+ case TargetPlatform.Web:
{
var buildDir = Path.Combine(root, "build-" + architecture.ToString());
diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs b/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs
index f67244c9b..29a8ff009 100644
--- a/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs
+++ b/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs
@@ -114,6 +114,7 @@ namespace Flax.Deps.Dependencies
case TargetPlatform.PS4:
case TargetPlatform.PS5:
case TargetPlatform.Switch:
+ case TargetPlatform.Web:
runtimeFlavor = "Mono";
setupVersion = true;
buildMonoAotCross = true;
@@ -128,6 +129,9 @@ namespace Flax.Deps.Dependencies
case TargetPlatform.Switch:
os = "switch";
break;
+ case TargetPlatform.Web:
+ os = "browser";
+ break;
default: throw new InvalidPlatformException(targetPlatform);
}
buildArgs = $" /p:RuntimeOS={os} -subset mono+libs -cmakeargs \"-DDISABLE_JIT=1-DENABLE_PERFTRACING=0-DDISABLE_REFLECTION_EMIT=1-DDISABLE_EVENTPIPE=1-DDISABLE_COM=1-DDISABLE_PROFILER=1-DDISABLE_COMPONENTS=1\" /p:FeaturePerfTracing=false /p:FeatureManagedEtw=false /p:FeatureManagedEtwChannels=false /p:FeatureEtw=false /p:ApiCompatValidateAssemblies=false";
diff --git a/Source/Tools/Flax.Build/Deps/Dependency.cs b/Source/Tools/Flax.Build/Deps/Dependency.cs
index 2b1de06ff..6f8add0a5 100644
--- a/Source/Tools/Flax.Build/Deps/Dependency.cs
+++ b/Source/Tools/Flax.Build/Deps/Dependency.cs
@@ -447,6 +447,7 @@ namespace Flax.Deps
public static void RunCmake(string path, TargetPlatform platform, TargetArchitecture architecture, string customArgs = null, Dictionary envVars = null)
{
string cmdLine;
+ string cmakeBinary = "cmake";
switch (platform)
{
case TargetPlatform.Windows:
@@ -516,13 +517,19 @@ namespace Flax.Deps
cmdLine = string.Format("CMakeLists.txt -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=\"{0}\" -DCMAKE_OSX_ARCHITECTURES={1}", Configuration.iOSMinVer, arch);
break;
}
+ case TargetPlatform.Web:
+ {
+ cmakeBinary = "emcmake.bat";
+ cmdLine = "cmake CMakeLists.txt";
+ break;
+ }
default: throw new InvalidPlatformException(platform);
}
if (customArgs != null)
cmdLine += " " + customArgs;
- Utilities.Run("cmake", cmdLine, null, path, Utilities.RunOptions.DefaultTool, envVars);
+ Utilities.Run(cmakeBinary, cmdLine, null, path, Utilities.RunOptions.DefaultTool, envVars);
}
///
diff --git a/Source/Tools/Flax.Build/Platforms/Web/EmscriptenSdk.cs b/Source/Tools/Flax.Build/Platforms/Web/EmscriptenSdk.cs
index 946fc0c87..b9169cafa 100644
--- a/Source/Tools/Flax.Build/Platforms/Web/EmscriptenSdk.cs
+++ b/Source/Tools/Flax.Build/Platforms/Web/EmscriptenSdk.cs
@@ -64,7 +64,7 @@ namespace Flax.Build.Platforms
versionStr = versionStr.Substring(1, versionStr.Length - 2);
Version = new Version(versionStr);
- var minVersion = new Version(4, 0);
+ var minVersion = new Version(3, 1);
if (Version < minVersion)
{
Log.Error(string.Format("Unsupported Emscripten SDK version {0}. Minimum supported is {1}.", Version, minVersion));
diff --git a/Source/Tools/Flax.Build/Platforms/Web/WebToolchain.cs b/Source/Tools/Flax.Build/Platforms/Web/WebToolchain.cs
index 115c67fed..117874710 100644
--- a/Source/Tools/Flax.Build/Platforms/Web/WebToolchain.cs
+++ b/Source/Tools/Flax.Build/Platforms/Web/WebToolchain.cs
@@ -100,6 +100,8 @@ namespace Flax.Build.Platforms
private void AddSharedArgs(List args, BuildOptions options, bool debugInformation, bool optimization)
{
+ //args.Add("-pthread");
+
if (debugInformation)
args.Add("-g2");
else
@@ -132,7 +134,7 @@ namespace Flax.Build.Platforms
if (options.LinkEnv.LinkTimeCodeGeneration)
args.Add("-flto");
- if (options.LinkEnv.Output == LinkerOutput.SharedLibrary)
+ //if (options.LinkEnv.Output == LinkerOutput.SharedLibrary)
args.Add("-fPIC");
var sanitizers = options.CompileEnv.Sanitizers;
@@ -158,8 +160,8 @@ namespace Flax.Build.Platforms
AddSharedArgs(commonArgs, options, options.CompileEnv.DebugInformation, options.CompileEnv.Optimization);
// Hack to pull SDL3 port via emcc
- if (options.CompileEnv.PreprocessorDefinitions.Contains("PLATFORM_SDL"))
- commonArgs.Add("--use-port=sdl3");
+ //if (options.CompileEnv.PreprocessorDefinitions.Contains("PLATFORM_SDL"))
+ // commonArgs.Add("--use-port=sdl3");
}
// Add preprocessor definitions
@@ -239,6 +241,168 @@ namespace Flax.Build.Platforms
return output;
}
+ public override bool CompileCSharp(ref CSharpOptions options)
+ {
+ switch (options.Action)
+ {
+ case CSharpOptions.ActionTypes.GetOutputFiles:
+ {
+ foreach (var inputFile in options.InputFiles)
+ {
+ string assemblyPath;
+ if (Configuration.AOTMode == DotNetAOTModes.MonoAOTDynamic)
+ assemblyPath = inputFile + Platform.SharedLibraryFileExtension;
+ else
+ assemblyPath = Path.Combine(Path.GetDirectoryName(inputFile), Platform.StaticLibraryFilePrefix + Path.GetFileName(inputFile) + Platform.StaticLibraryFileExtension);
+
+ if (Path.GetFileNameWithoutExtension(inputFile) == "System.Private.CoreLib")
+ {
+ // Use pre-compiled binaries
+ DotNetSdk.Instance.GetHostRuntime(TargetPlatform.Web, TargetArchitecture.x86, out var hostRuntime);
+ assemblyPath = Path.Combine(hostRuntime.Path, "libmonosgen-2.0.a");
+ }
+ options.OutputFiles.Add(assemblyPath);
+ }
+ return false;
+ }
+ case CSharpOptions.ActionTypes.GetPlatformTools:
+ {
+ string arch = Platform.BuildTargetArchitecture switch
+ {
+ TargetArchitecture.x64 => "x64",
+ TargetArchitecture.ARM64 => "arm64",
+ _ => throw new PlatformNotSupportedException(Platform.BuildTargetArchitecture.ToString()),
+ };
+ string os;
+ switch (Platform.BuildPlatform.Target)
+ {
+ case TargetPlatform.Windows:
+ os = "win";
+ break;
+ default:
+ throw new PlatformNotSupportedException(Platform.BuildPlatform.Target.ToString());
+ }
+
+ options.PlatformToolsPath = Path.Combine(DotNetSdk.SelectVersionFolder(Path.Combine(DotNetSdk.Instance.RootPath, $"packs/Microsoft.NETCore.App.Runtime.AOT.{os}-{arch}.Cross.browser-wasm")), "tools");
+ return false;
+ }
+ case CSharpOptions.ActionTypes.MonoCompile:
+ {
+ string binaryExtension = Platform.BuildPlatform.Target == TargetPlatform.Windows ? ".exe" : "";
+ var aotCompilerPath = Path.Combine(options.PlatformToolsPath, "mono-aot-cross") + binaryExtension;
+ //var clangPath = Path.Combine(ToolchainPath, "usr/bin/clang");
+
+ var inputFile = options.InputFiles[0];
+ var inputFileAsm = inputFile + ".s";
+ var inputFileObj = inputFile + ".o";
+ var outputFileDylib = options.OutputFiles[0];
+ var inputFileFolder = Path.GetDirectoryName(inputFile);
+
+ if (Path.GetFileNameWithoutExtension(inputFile) == "System.Private.CoreLib")
+ {
+ // Pre-compiled, skip
+ return false;
+ }
+
+ string outputFile;
+ {
+ if (Configuration.AOTMode == DotNetAOTModes.MonoAOTDynamic)
+ outputFile = inputFile + Platform.SharedLibraryFileExtension;
+ else
+ outputFile = Path.Combine(Path.GetDirectoryName(inputFile), Platform.StaticLibraryFilePrefix + Path.GetFileName(inputFile) + Platform.StaticLibraryFileExtension);
+ }
+
+ // Setup options
+ bool debugSymbols = options.EnableDebugSymbols;
+ bool useLLVM = true;
+ //if (useLLVM)
+ debugSymbols = false;
+ var llvmPath = "\"C:\\Program Files\\LLVM\\bin\"";//Path.Combine(EmscriptenSdk.Instance.EmscriptenPath, "bin");
+
+ var monoAotMode = "full";
+ var monoDebugMode = debugSymbols ? "soft-debug" : "nodebug";
+ var aotCompilerArgs = $"--verbose{(useLLVM ? " --llvm" : "")} --aot={monoAotMode},llvmonly,verbose,stats,print-skipped,{monoDebugMode}{(useLLVM ? ",llvm-outfile="+Path.GetFileName(outputFile) : "")} -O=float32";
+ //var aotCompilerArgs = $"{(useLLVM ? " --llvm" : "")} --aot=static,llvmonly,verbose,stats,print-skipped,llvm-path={llvmPath},{monoDebugMode}{(useLLVM ? ",llvm-outfile=" + Path.GetFileName(outputFile) : "")} -O=float32";
+ //var aotCompilerArgs = $"{(useLLVM ? " --llvm" : "")} --aot=static,llvmonly,verbose,stats,print-skipped,{monoDebugMode}{(useLLVM ? ",llvm-outfile=" + Path.GetFileName(outputFile) : "")} -O=float32";
+ //if (debugSymbols || options.EnableToolDebug)
+ // aotCompilerArgs = "--debug " + aotCompilerArgs;
+
+ var envVars = new Dictionary();
+ envVars["MONO_PATH"] = options.AssembliesPath + ":" + options.ClassLibraryPath;
+ if (options.EnableToolDebug)
+ {
+ envVars["MONO_LOG_LEVEL"] = "debug";
+ }
+
+ //envVars["MONO_DEBUG"] = "gen-seq-points";
+
+
+ // Run cross-compiler compiler (outputs assembly code)
+ int result = Utilities.Run(aotCompilerPath, $"{aotCompilerArgs} \"{inputFile}\"", null, inputFileFolder, Utilities.RunOptions.AppMustExist | Utilities.RunOptions.ConsoleLogOutput, envVars);
+ if (result != 0)
+ return true;
+
+ // Get build args for iOS
+ /*var clangArgs = new List();
+ AddArgsCommon(null, clangArgs);
+ var clangArgsText = string.Join(" ", clangArgs);
+
+ // Build object file
+ result = Utilities.Run(clangPath, $"\"{inputFileAsm}\" -c -o \"{inputFileObj}\" " + clangArgsText, null, inputFileFolder, Utilities.RunOptions.AppMustExist | Utilities.RunOptions.ConsoleLogOutput, envVars);
+ if (result != 0)
+ return true;
+
+ // Build dylib file
+ result = Utilities.Run(clangPath, $"\"{inputFileObj}\" -dynamiclib -fPIC -o \"{outputFileDylib}\" " + clangArgsText, null, inputFileFolder, Utilities.RunOptions.AppMustExist | Utilities.RunOptions.ConsoleLogOutput, envVars);
+ if (result != 0)
+ return true;
+
+ // Clean intermediate results
+ File.Delete(inputFileAsm);
+ File.Delete(inputFileObj);
+
+ // Fix rpath id
+ result = Utilities.Run("install_name_tool", $"-id \"@rpath/{Path.GetFileName(outputFileDylib)}\" \"{outputFileDylib}\"", null, inputFileFolder, Utilities.RunOptions.ConsoleLogOutput, envVars);
+ if (result != 0)
+ return true;*/
+
+ return false;
+ }
+ }
+ return base.CompileCSharp(ref options);
+ }
+#if false
+ ///
+ public override bool CompileCSharp(ref CSharpOptions options)
+ {
+ switch (options.Action)
+ {
+ case CSharpOptions.ActionTypes.MonoCompile:
+ {
+ var aotCompilerPath = Path.Combine(options.PlatformToolsPath, "mono-aot-cross.exe");
+
+ // Setup options
+ var monoAotMode = "full";
+ var monoDebugMode = options.EnableDebugSymbols ? "soft-debug" : "nodebug";
+ var aotCompilerArgs = $"--aot={monoAotMode},verbose,stats,print-skipped,{monoDebugMode} -O=all";
+ if (options.EnableDebugSymbols || options.EnableToolDebug)
+ aotCompilerArgs = "--debug " + aotCompilerArgs;
+ var envVars = new Dictionary();
+ envVars["MONO_PATH"] = options.AssembliesPath + ";" + options.ClassLibraryPath;
+ if (options.EnableToolDebug)
+ {
+ envVars["MONO_LOG_LEVEL"] = "debug";
+ }
+
+ // Run cross-compiler compiler
+ int result = Utilities.Run(aotCompilerPath, $"{aotCompilerArgs} \"{options.InputFiles[0]}\"", null, ""/*options.PlatformToolsPath*/, Utilities.RunOptions.AppMustExist | Utilities.RunOptions.ConsoleLogOutput, envVars);
+ return result != 0;
+ }
+ }
+ return base.CompileCSharp(ref options);
+ }
+#endif
+
private Task CreateBinary(TaskGraph graph, BuildOptions options, string outputFilePath)
{
var task = graph.Add();
@@ -276,6 +440,8 @@ namespace Flax.Build.Platforms
}
}
+ args.Add("-Wl,--allow-multiple-definition"); // Multiple pthread-related definitions in dotnet runtime
+
args.Add("-Wl,--start-group");
// Input libraries
@@ -310,6 +476,7 @@ namespace Flax.Build.Platforms
{
task.PrerequisiteFiles.Add(library);
args.Add(string.Format("\"-l{0}\"", GetLibName(library)));
+ libraryPaths.Add(dir); // FIXME
}
}
diff --git a/Source/Tools/Flax.Build/Program.cs b/Source/Tools/Flax.Build/Program.cs
index 711ac5ccb..6ca0fdff3 100644
--- a/Source/Tools/Flax.Build/Program.cs
+++ b/Source/Tools/Flax.Build/Program.cs
@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
+using System.Reflection;
using System.Threading;
using Flax.Deploy;
using Flax.Deps;
@@ -173,6 +174,10 @@ namespace Flax.Build
}
catch (Exception ex)
{
+ // Skip the exception thrown from failed method invocation
+ if (ex is TargetInvocationException && ex.InnerException != null)
+ ex = ex.InnerException;
+
// Ignore exception logging for build errors
if (!(ex is BuildException))
Log.Exception(ex);