From 8cf6979f90a46304bc343ce3b61da8e2cfcfb4df Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Sun, 15 Mar 2026 22:45:36 +0200 Subject: [PATCH] _some prog with dynamic linking perhaps --- .../Cooker/Platform/Web/WebPlatformTools.cpp | 2 +- .../WebGPU/GraphicsDeviceWebGPU.Build.cs | 2 +- Source/Engine/Renderer/ShadowsPass.cpp | 2 +- Source/Engine/Scripting/Runtime/DotNet.cpp | 5 ++ .../Flax.Build/Build/DotNet/DotNetAOT.cs | 76 ++++++++++++++++++- .../Flax.Build/Platforms/Web/WebToolchain.cs | 47 ++++++++++-- 6 files changed, 121 insertions(+), 13 deletions(-) diff --git a/Source/Editor/Cooker/Platform/Web/WebPlatformTools.cpp b/Source/Editor/Cooker/Platform/Web/WebPlatformTools.cpp index c235a8e90..ab0862a37 100644 --- a/Source/Editor/Cooker/Platform/Web/WebPlatformTools.cpp +++ b/Source/Editor/Cooker/Platform/Web/WebPlatformTools.cpp @@ -49,7 +49,7 @@ ArchitectureType WebPlatformTools::GetArchitecture() const DotNetAOTModes WebPlatformTools::UseAOT() const { - return DotNetAOTModes::MonoAOTStatic;// DotNetAOTModes::None;//DotNetAOTModes::MonoAOTStatic;//DotNetAOTModes::NoDotnet; + return DotNetAOTModes::MonoAOTDynamic;//MonoAOTStatic;// DotNetAOTModes::None;//DotNetAOTModes::MonoAOTStatic;//DotNetAOTModes::NoDotnet; } PixelFormat WebPlatformTools::GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format) diff --git a/Source/Engine/GraphicsDevice/WebGPU/GraphicsDeviceWebGPU.Build.cs b/Source/Engine/GraphicsDevice/WebGPU/GraphicsDeviceWebGPU.Build.cs index def5a7f8f..f8fc215df 100644 --- a/Source/Engine/GraphicsDevice/WebGPU/GraphicsDeviceWebGPU.Build.cs +++ b/Source/Engine/GraphicsDevice/WebGPU/GraphicsDeviceWebGPU.Build.cs @@ -18,7 +18,7 @@ public class GraphicsDeviceWebGPU : GraphicsDeviceBaseModule options.CompileEnv.CustomArgs.Add(port); options.LinkEnv.CustomArgs.Add("-sASYNCIFY"); options.OutputFiles.Add(port); - options.PublicDefinitions.Add("GRAPHICS_API_WEBGPU"); + //options.PublicDefinitions.Add("GRAPHICS_API_WEBGPU"); options.PrivateIncludePaths.Add(Path.Combine(EmscriptenSdk.Instance.EmscriptenPath, "emscripten/cache/ports/emdawnwebgpu/emdawnwebgpu_pkg/webgpu/include")); options.PrivateDependencies.Add("lz4"); } diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp index 18bf57ea8..5e85afdb6 100644 --- a/Source/Engine/Renderer/ShadowsPass.cpp +++ b/Source/Engine/Renderer/ShadowsPass.cpp @@ -1175,7 +1175,7 @@ void ShadowsPass::SetupShadows(RenderContext& renderContext, RenderContextBatch& LOG(Fatal, "Failed to setup shadow map of size {0}x{1} and format {2}", desc.Width, desc.Height, ScriptingEnum::ToString(desc.Format)); return; } -#if PLATFORM_WEB +#if PLATFORM_WEB && GRAPHICS_API_WEBGPU // Hack to fix WebGPU limitation that requires to specify different sampler type manually to sample depth texture void SetWebGPUTextureViewSampler(GPUTextureView * view, uint32 samplerType); SetWebGPUTextureViewSampler(shadows.ShadowMapAtlas->View(), 0x00000004); // WGPUTextureSampleType_Depth diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index eb00bf2af..966b09d36 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -2075,6 +2075,11 @@ static MonoAssembly* OnMonoAssemblyLoad(const char* aname) #if DOTNET_HOST_MONO_DEBUG LOG(Info, "Loading C# assembly from path = {0}, exist = {1}", path, FileSystem::FileExists(path)); #endif + String testPath = path; + testPath += TEXT(".so"); + LOG(Info, "{0} exist = {1}", testPath, FileSystem::FileExists(testPath)); + //Platform::LoadLibrary(testPath.Get()); + MonoAssembly* assembly = nullptr; if (FileSystem::FileExists(path)) { diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetAOT.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetAOT.cs index 58b3088df..f23468ba3 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/DotNetAOT.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetAOT.cs @@ -2,6 +2,7 @@ using Mono.Cecil; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; @@ -420,7 +421,18 @@ namespace Flax.Build rmdir /S /Q %command% """ ); + /*Utilities.WriteFileIfChanged(Path.Combine(Path.GetDirectoryName(inputFiles[0]), "rm.bat"), + """ + @echo off + setlocal enabledelayedexpansion + set command=%* + set command=!command:~3! + del /F /Q /S %command% + rmdir /S /Q %command% + """ + );*/ + ConcurrentBag outputStaticLibraryFiles = new (); var compileAssembly = (string assemblyPath) => { //if (!assemblyPath.Contains("Newtonsoft")) @@ -493,8 +505,9 @@ namespace Flax.Build // Copy AOT build products foreach (var outputFile in options.OutputFiles) { + outputStaticLibraryFiles.Add(outputFile); // Skip if deployed file is already valid - var deployedFilePath = Path.Combine(dotnetOutputPath, Path.GetFileName(outputFile)); + /*var deployedFilePath = Path.Combine(dotnetOutputPath, Path.GetFileName(outputFile)); if (!File.Exists(deployedFilePath) || File.GetLastWriteTime(outputFile) > File.GetLastWriteTime(deployedFilePath)) { // Copy to the destination folder @@ -502,7 +515,7 @@ namespace Flax.Build if (useDebug && File.Exists(outputFile + ".pdb")) Utilities.FileCopy(outputFile + ".pdb", Path.Combine(dotnetOutputPath, Path.GetFileName(outputFile + ".pdb"))); validCache = false; - } + }*/ } } else @@ -554,6 +567,65 @@ namespace Flax.Build throw new Exception("Mono AOT failed to link static libraries into a shared module"); } } + else if (Configuration.AOTMode == DotNetAOTModes.MonoAOTDynamic) + { + var linkAssembly = (string outputFile) => + { + Log.Info(""); + Log.Warning(" " + Path.GetFileNameWithoutExtension(outputFile)); + Log.Info(""); + + // Get output file path for this assembly (platform can use custom extension) + var options = new Toolchain.CSharpOptions + { + Action = Toolchain.CSharpOptions.ActionTypes.MonoLink, + InputFiles = [Path.Combine(Path.GetDirectoryName(outputFile), Path.GetFileNameWithoutExtension(outputFile))], + OutputFiles = [outputFile], + AssembliesPath = aotAssembliesPath, + //ClassLibraryPath = dotnetLibPath, + PlatformToolsPath = Path.GetDirectoryName(outputFile), + //EnableDebugSymbols = useDebug, + //EnableToolDebug = dotnetAotDebug, + }; + if (!File.Exists(outputFile) && buildToolchain.CompileCSharp(ref options)) + { + Log.Error("Failed to run linker on assembly " + outputFile); + failed = true; + return; + } + + // Skip if deployed file is already valid + var deployedFilePath = Path.Combine(dotnetOutputPath, Path.GetFileName(outputFile)); + if (!File.Exists(deployedFilePath) || File.GetLastWriteTime(outputFile) > File.GetLastWriteTime(deployedFilePath)) + { + // Copy to the destination folder + Utilities.FileCopy(outputFile, deployedFilePath); + if (/*useDebug &&*/ File.Exists(outputFile + ".pdb")) + Utilities.FileCopy(outputFile + ".pdb", Path.Combine(dotnetOutputPath, Path.GetFileName(outputFile + ".pdb"))); + validCache = false; + } + }; + + // Run final linking with single-threaded as this is very memory intensive process + if (Configuration.MaxConcurrency > 1 && Configuration.ConcurrencyProcessorScale > 0.0f && !dotnetAotDebug) + { + // Multi-threaded + var outputFiles = outputStaticLibraryFiles.OrderBy(x => x.Contains("System.Private.CoreLib") || x.Contains("System.Linq") || x.Contains("System.Private.Xml") ? 0 : 1).ToArray(); // Process the file which takes longest time first + System.Threading.Tasks.Parallel.ForEach(outputFiles/*, new System.Threading.Tasks.ParallelOptions() { MaxDegreeOfParallelism = Math.Min(8, Configuration.MaxConcurrency) }*/, linkAssembly); + } + else + { + foreach (var outputFile in outputStaticLibraryFiles) + { + linkAssembly(outputFile); + if (failed) + break; + } + } + + if (failed) + throw new Exception($"Failed to run AOT. See log ({Configuration.LogFile})."); + } } else { diff --git a/Source/Tools/Flax.Build/Platforms/Web/WebToolchain.cs b/Source/Tools/Flax.Build/Platforms/Web/WebToolchain.cs index fb074cb59..f7bb41181 100644 --- a/Source/Tools/Flax.Build/Platforms/Web/WebToolchain.cs +++ b/Source/Tools/Flax.Build/Platforms/Web/WebToolchain.cs @@ -321,12 +321,12 @@ namespace Flax.Build.Platforms var initialMemory = Configuration.WebInitialMemory; //if (options.CompileEnv.Sanitizers.HasFlag(Sanitizer.Address)) // initialMemory = Math.Max(initialMemory, 64); // Address Sanitizer needs more memory - /*args.Add($"-sINITIAL_MEMORY={initialMemory}MB"); + args.Add($"-sINITIAL_MEMORY={initialMemory}MB"); args.Add("-sSTACK_SIZE=4MB"); args.Add("-sALLOW_MEMORY_GROWTH=1"); // Setup file access (Game Cooker packs files with file_packager tool) - args.Add("-sFORCE_FILESYSTEM");*/ + args.Add("-sFORCE_FILESYSTEM"); //args.Add("-sLZ4"); // https://emscripten.org/docs/compiling/Dynamic-Linking.html#dynamic-linking @@ -342,6 +342,12 @@ namespace Flax.Build.Platforms } } + args.Add("-O0"); + + args.Add("--verbose"); + + //args.Add("--trace"); + args.Add("-Wl,--allow-multiple-definition"); // Multiple pthread-related definitions in dotnet runtime args.Add("-Wl,--start-group"); @@ -380,6 +386,12 @@ namespace Flax.Build.Platforms args.Add(string.Format("\"-l{0}\"", GetLibName(library))); libraryPaths.Add(dir); // FIXME }*/ + + /*if (library.Contains("net10.0")) + { + if (!library.Contains("System.Private.CoreLib")) + continue; + }*/ args.Add(library.Replace(Path.DirectorySeparatorChar, '/') + Platform.StaticLibraryFileExtension); } @@ -415,7 +427,9 @@ namespace Flax.Build.Platforms //task.CommandPath = _compilerPath; //task.CommandArguments = string.Join(" ", args); - int result = Utilities.Run(NativeCompilerPath, $"{string.Join(" ", args)}", null, Path.GetDirectoryName(options.OutputFiles[0]), Utilities.RunOptions.AppMustExist | Utilities.RunOptions.ConsoleLogOutput); + //int result = Utilities.Run(NativeCompilerPath, $"{string.Join(" ", args)}", null, Path.GetDirectoryName(options.OutputFiles[0]), Utilities.RunOptions.AppMustExist | Utilities.RunOptions.ConsoleLogOutput); + int result = Utilities.Run(NativeCompilerPath, $"{string.Join(" ", args)}", null, options.PlatformToolsPath, Utilities.RunOptions.AppMustExist | Utilities.RunOptions.ConsoleLogOutput); + if (result != 0) return true; @@ -441,9 +455,9 @@ namespace Flax.Build.Platforms string outputFile; { - if (Configuration.AOTMode == DotNetAOTModes.MonoAOTDynamic) + /*if (Configuration.AOTMode == DotNetAOTModes.MonoAOTDynamic) outputFile = inputFile + Platform.SharedLibraryFileExtension; - else + else*/ outputFile = Path.Combine(Path.GetDirectoryName(inputFile), Platform.StaticLibraryFilePrefix + Path.GetFileName(inputFile) + Platform.StaticLibraryFileExtension); } @@ -452,15 +466,17 @@ namespace Flax.Build.Platforms bool useLLVM = true; //if (useLLVM) debugSymbols = false; - var llvmPath = "\"C:\\Program Files\\LLVM\\bin\"";//Path.Combine(EmscriptenSdk.Instance.EmscriptenPath, "bin"); + //var llvmPath = "\"C:\\Program Files\\LLVM\\bin\"";//Path.Combine(EmscriptenSdk.Instance.EmscriptenPath, "bin"); + var llvmPath = "\"" + Path.Combine(EmscriptenSdk.Instance.EmscriptenPath, "bin") + "\""; var monoAotMode = "full"; if (useLLVM) - monoAotMode = "llvmonly"; + monoAotMode = "no-opt,llvmonly";//"llvmonly"; //if ("mscorlib.dll" == "") // monoAotMode = "interp"; var monoDebugMode = debugSymbols ? "soft-debug" : "nodebug"; + //var aotCompilerArgs = $"{(useLLVM ? "--llvm" : "")} --aot={monoAotMode},asmonly,verbose,stats,print-skipped,{monoDebugMode}{(useLLVM ? $",llvm-path={llvmPath},llvm-outfile=" + Path.GetFileName(outputFile) : "")} -O=float32"; var aotCompilerArgs = $"{(useLLVM ? "--llvm" : "")} --aot={monoAotMode},asmonly,verbose,stats,print-skipped,{monoDebugMode}{(useLLVM ? $",llvm-path={llvmPath},llvm-outfile=" + Path.GetFileName(outputFile) : "")} -O=float32"; //aotCompilerArgs += " --verbose"; @@ -479,13 +495,28 @@ namespace Flax.Build.Platforms } //envVars["MONO_DEBUG"] = "gen-seq-points"; - + // Run cross-compiler compiler (outputs assembly code) + //int result = 0; int result = Utilities.Run(aotCompilerPath, $"{aotCompilerArgs} \"{inputFile}\"", null, inputFileFolder, Utilities.RunOptions.AppMustExist | Utilities.RunOptions.ConsoleLogOutput, envVars); if (result != 0) return true; + /*CSharpOptions soOptions = new CSharpOptions() + { + Action = CSharpOptions.ActionTypes.MonoLink, + InputFiles = [Path.Combine(Path.GetDirectoryName(inputFile), Platform.StaticLibraryFilePrefix + Path.GetFileName(inputFile))], + OutputFiles = [ inputFile + Platform.SharedLibraryFileExtension ], + AssembliesPath = options.AssembliesPath, + PlatformToolsPath = inputFileFolder, + }; + return CompileCSharp(ref soOptions);*/ + + /*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);