4 Commits

Author SHA1 Message Date
8cf6979f90 _some prog with dynamic linking perhaps
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2026-03-15 22:45:36 +02:00
1ff4ac0402 _maybe prog, trying static linking 2026-03-14 15:50:15 +02:00
801f0f7432 _some prog, needs aot for corlib 2026-03-14 15:50:15 +02:00
8b605dff89 _baseline emscripten build 2026-03-14 15:49:23 +02:00
28 changed files with 641 additions and 60 deletions

View File

@@ -1,4 +1,4 @@
# Redirect to our own Git LFS server # Redirect to our own Git LFS server
[lfs] [lfs]
url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs" #url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs"
locksverify = false locksverify = false

View File

@@ -49,7 +49,7 @@ ArchitectureType WebPlatformTools::GetArchitecture() const
DotNetAOTModes WebPlatformTools::UseAOT() const DotNetAOTModes WebPlatformTools::UseAOT() const
{ {
return DotNetAOTModes::NoDotnet; return DotNetAOTModes::MonoAOTDynamic;//MonoAOTStatic;// DotNetAOTModes::None;//DotNetAOTModes::MonoAOTStatic;//DotNetAOTModes::NoDotnet;
} }
PixelFormat WebPlatformTools::GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format) PixelFormat WebPlatformTools::GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format)
@@ -166,8 +166,9 @@ bool WebPlatformTools::OnPostProcess(CookingData& data)
// Move .wasm assemblies into the data files in order for dlopen to work (blocking) // Move .wasm assemblies into the data files in order for dlopen to work (blocking)
{ {
Array<String> files; Array<String> files, files2;
FileSystem::DirectoryGetFiles(files, data.OriginalOutputPath, TEXT("*.wasm"), DirectorySearchOption::AllDirectories); FileSystem::DirectoryGetFiles(files, data.OriginalOutputPath, TEXT("*.wasm"), DirectorySearchOption::AllDirectories);
FileSystem::DirectoryGetFiles(files, data.OriginalOutputPath, TEXT("*.so"), DirectorySearchOption::AllDirectories);
StringView gameWasm = StringUtils::GetFileNameWithoutExtension(gameJs); StringView gameWasm = StringUtils::GetFileNameWithoutExtension(gameJs);
for (const String& file : files) for (const String& file : files)
{ {
@@ -175,6 +176,12 @@ bool WebPlatformTools::OnPostProcess(CookingData& data)
continue; // Skip the main game module continue; // Skip the main game module
FileSystem::MoveFile(data.DataOutputPath / StringUtils::GetFileName(file), file, true); FileSystem::MoveFile(data.DataOutputPath / StringUtils::GetFileName(file), file, true);
} }
for (const String& file : files2)
{
if (StringUtils::GetFileNameWithoutExtension(file) == gameWasm)
continue; // Skip the main game module
FileSystem::MoveFile(data.DataOutputPath / StringUtils::GetFileName(file), file, true);
}
} }
// Pack data files into a single file using Emscripten's file_packager tool // Pack data files into a single file using Emscripten's file_packager tool

View File

@@ -37,8 +37,8 @@ void PrecompileAssembliesStep::OnBuildStarted(CookingData& data)
if (cachedData != aotModeCacheValue) if (cachedData != aotModeCacheValue)
{ {
LOG(Info, "AOT cache invalidation"); LOG(Info, "AOT cache invalidation");
FileSystem::DeleteDirectory(data.ManagedCodeOutputPath); // Remove AOT cache //FileSystem::DeleteDirectory(data.ManagedCodeOutputPath); // Remove AOT cache
FileSystem::DeleteDirectory(data.DataOutputPath / TEXT("Dotnet")); // Remove deployed Dotnet libs (be sure to remove any leftovers from previous build) //FileSystem::DeleteDirectory(data.DataOutputPath / TEXT("Dotnet")); // Remove deployed Dotnet libs (be sure to remove any leftovers from previous build)
} }
} }
if (!FileSystem::DirectoryExists(data.ManagedCodeOutputPath)) if (!FileSystem::DirectoryExists(data.ManagedCodeOutputPath))

View File

@@ -121,7 +121,7 @@ namespace FlaxEditor.GUI
} }
// Select the first platform // Select the first platform
_selected = platforms[0].PlatformType; _selected = PlatformType.Web;
((Image)Children[0]).Color = _selectedColor; ((Image)Children[0]).Color = _selectedColor;
((Image)Children[0]).MouseOverColor = _selectedColor; ((Image)Children[0]).MouseOverColor = _selectedColor;
} }

View File

@@ -83,7 +83,7 @@ namespace FlaxEditor.Windows
public bool ShowOutput = true; public bool ShowOutput = true;
[EditorOrder(20), Tooltip("Configuration build mode")] [EditorOrder(20), Tooltip("Configuration build mode")]
public BuildConfiguration ConfigurationMode = BuildConfiguration.Development; public BuildConfiguration ConfigurationMode = BuildConfiguration.Debug;
[EditorOrder(90), Tooltip("The list of custom defines passed to the build tool when compiling project scripts. Can be used in build scripts for configuration (Configuration.CustomDefines).")] [EditorOrder(90), Tooltip("The list of custom defines passed to the build tool when compiling project scripts. Can be used in build scripts for configuration (Configuration.CustomDefines).")]
public string[] CustomDefines; public string[] CustomDefines;

View File

@@ -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); Log.WarningOnce(string.Format("Building for {0} without Vulkan rendering backend (Vulkan SDK is missing)", options.Platform.Target), ref _logMissingVulkanSDK);
break; break;
case TargetPlatform.Web: case TargetPlatform.Web:
options.PrivateDependencies.Add("GraphicsDeviceWebGPU"); options.PrivateDependencies.Add("GraphicsDeviceNull");
//options.PrivateDependencies.Add("GraphicsDeviceWebGPU");
break; break;
default: throw new InvalidPlatformException(options.Platform.Target); default: throw new InvalidPlatformException(options.Platform.Target);
} }

View File

@@ -18,7 +18,7 @@ public class GraphicsDeviceWebGPU : GraphicsDeviceBaseModule
options.CompileEnv.CustomArgs.Add(port); options.CompileEnv.CustomArgs.Add(port);
options.LinkEnv.CustomArgs.Add("-sASYNCIFY"); options.LinkEnv.CustomArgs.Add("-sASYNCIFY");
options.OutputFiles.Add(port); 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.PrivateIncludePaths.Add(Path.Combine(EmscriptenSdk.Instance.EmscriptenPath, "emscripten/cache/ports/emdawnwebgpu/emdawnwebgpu_pkg/webgpu/include"));
options.PrivateDependencies.Add("lz4"); options.PrivateDependencies.Add("lz4");
} }

View File

@@ -6,6 +6,7 @@ namespace FlaxEngine
{ {
partial class CollisionData partial class CollisionData
{ {
#if false
/// <summary> /// <summary>
/// Cooks the mesh collision data and updates the virtual asset. action cannot be performed on a main thread. /// 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] /// [Deprecated on 16.06.2022, expires on 16.06.2024]
@@ -68,5 +69,6 @@ namespace FlaxEngine
for (int i = 0; i < tmp.Length; i++) for (int i = 0; i < tmp.Length; i++)
vertexBuffer[i] = tmp[i]; vertexBuffer[i] = tmp[i];
} }
#endif
} }
} }

View File

@@ -30,4 +30,8 @@
#define GPU_ENABLE_ASYNC_RESOURCES_CREATION 0 #define GPU_ENABLE_ASYNC_RESOURCES_CREATION 0
#endif #endif
// Use AOT for Mono
#define USE_MONO_AOT 1
#define USE_MONO_AOT_MODE MONO_AOT_MODE_INTERP
#endif #endif

View File

@@ -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)); LOG(Fatal, "Failed to setup shadow map of size {0}x{1} and format {2}", desc.Width, desc.Height, ScriptingEnum::ToString(desc.Format));
return; 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 // Hack to fix WebGPU limitation that requires to specify different sampler type manually to sample depth texture
void SetWebGPUTextureViewSampler(GPUTextureView * view, uint32 samplerType); void SetWebGPUTextureViewSampler(GPUTextureView * view, uint32 samplerType);
SetWebGPUTextureViewSampler(shadows.ShadowMapAtlas->View(), 0x00000004); // WGPUTextureSampleType_Depth SetWebGPUTextureViewSampler(shadows.ShadowMapAtlas->View(), 0x00000004); // WGPUTextureSampleType_Depth

View File

@@ -51,7 +51,7 @@
#include <mono/metadata/mono-gc.h> #include <mono/metadata/mono-gc.h>
#include <mono/metadata/mono-private-unstable.h> #include <mono/metadata/mono-private-unstable.h>
typedef char char_t; typedef char char_t;
#define DOTNET_HOST_MONO_DEBUG 0 #define DOTNET_HOST_MONO_DEBUG 1
#ifdef USE_MONO_AOT_MODULE #ifdef USE_MONO_AOT_MODULE
void* MonoAotModuleHandle = nullptr; void* MonoAotModuleHandle = nullptr;
#endif #endif
@@ -270,6 +270,36 @@ struct NativePropertyDefinitions
MMethodAttributes setterAttributes; 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) MDomain* MCore::CreateDomain(const StringAnsi& domainName)
{ {
return nullptr; return nullptr;
@@ -2031,10 +2061,10 @@ static MonoAssembly* OnMonoAssemblyLoad(const char* aname)
String fileName = name; String fileName = name;
if (!name.EndsWith(TEXT(".dll")) && !name.EndsWith(TEXT(".exe"))) if (!name.EndsWith(TEXT(".dll")) && !name.EndsWith(TEXT(".exe")))
fileName += TEXT(".dll"); fileName += TEXT(".dll");
String path = Globals::ProjectFolder / String(TEXT("/Dotnet/")) / fileName; String path = Globals::ProjectFolder / String(TEXT("Dotnet/")) / fileName;
if (!FileSystem::FileExists(path)) if (!FileSystem::FileExists(path))
{ {
path = Globals::ProjectFolder / String(TEXT("/Dotnet/shared/Microsoft.NETCore.App/")) / fileName; path = Globals::ProjectFolder / String(TEXT("Dotnet/shared/Microsoft.NETCore.App/")) / fileName;
if (!FileSystem::FileExists(path)) if (!FileSystem::FileExists(path))
{ {
path = fileName; path = fileName;
@@ -2045,6 +2075,11 @@ static MonoAssembly* OnMonoAssemblyLoad(const char* aname)
#if DOTNET_HOST_MONO_DEBUG #if DOTNET_HOST_MONO_DEBUG
LOG(Info, "Loading C# assembly from path = {0}, exist = {1}", path, FileSystem::FileExists(path)); LOG(Info, "Loading C# assembly from path = {0}, exist = {1}", path, FileSystem::FileExists(path));
#endif #endif
String testPath = path;
testPath += TEXT(".so");
LOG(Info, "{0} exist = {1}", testPath, FileSystem::FileExists(testPath));
//Platform::LoadLibrary(testPath.Get());
MonoAssembly* assembly = nullptr; MonoAssembly* assembly = nullptr;
if (FileSystem::FileExists(path)) if (FileSystem::FileExists(path))
{ {
@@ -2205,7 +2240,7 @@ bool InitHostfxr()
#if defined(USE_MONO_AOT_MODE) #if defined(USE_MONO_AOT_MODE)
// Enable AOT mode (per-platform) // Enable AOT mode (per-platform)
mono_jit_set_aot_mode(USE_MONO_AOT_MODE); mono_jit_set_aot_mode(MONO_AOT_MODE_FULL);
#endif #endif
// Platform-specific setup // Platform-specific setup

View File

@@ -176,16 +176,19 @@ void onEngineUnloading(MAssembly* assembly);
bool ScriptingService::Init() bool ScriptingService::Init()
{ {
LOG(Info, "ScriptingService::Init");
PROFILE_MEM(Scripting); PROFILE_MEM(Scripting);
Stopwatch stopwatch; Stopwatch stopwatch;
// Initialize managed runtime // Initialize managed runtime
LOG(Info, "ScriptingService::Init MCore::LoadEngine");
if (MCore::LoadEngine()) if (MCore::LoadEngine())
{ {
LOG(Fatal, "C# runtime initialization failed."); LOG(Fatal, "C# runtime initialization failed.");
return true; return true;
} }
LOG(Info, "ScriptingService::Init MCore::CreateScriptingAssemblyLoadContext");
MCore::CreateScriptingAssemblyLoadContext(); MCore::CreateScriptingAssemblyLoadContext();
// Cache root domain // Cache root domain

View File

@@ -46,8 +46,9 @@ public class SDL : EngineDepsModule
options.OutputFiles.Add(Path.Combine(depsRoot, "libSDL3.a")); options.OutputFiles.Add(Path.Combine(depsRoot, "libSDL3.a"));
break; break;
case TargetPlatform.Web: case TargetPlatform.Web:
options.OutputFiles.Add("--use-port=sdl3"); //options.OutputFiles.Add("--use-port=sdl3");
return; options.OutputFiles.Add(Path.Combine(depsRoot, "libSDL3.a"));
break;
default: throw new InvalidPlatformException(options.Platform.Target); default: throw new InvalidPlatformException(options.Platform.Target);
} }

View File

@@ -104,6 +104,47 @@ public class nethost : ThirdPartyModule
options.PublicDefinitions.Add("USE_MONO_DYNAMIC_LIB"); options.PublicDefinitions.Add("USE_MONO_DYNAMIC_LIB");
options.DependencyFiles.Add(Path.Combine(hostRuntime.Path, "libmonosgen-2.0.dylib")); options.DependencyFiles.Add(Path.Combine(hostRuntime.Path, "libmonosgen-2.0.dylib"));
options.Libraries.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; break;
default: throw new InvalidPlatformException(options.Platform.Target); default: throw new InvalidPlatformException(options.Platform.Target);
} }

View File

@@ -2,6 +2,7 @@
using Mono.Cecil; using Mono.Cecil;
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -24,6 +25,11 @@ namespace Flax.Build
/// </summary> /// </summary>
ILC, ILC,
/// <summary>
///
/// </summary>
WebCIL,
/// <summary> /// <summary>
/// Use Mono AOT to cross-compile all used C# assemblies into native platform shared libraries. /// Use Mono AOT to cross-compile all used C# assemblies into native platform shared libraries.
/// </summary> /// </summary>
@@ -318,6 +324,8 @@ namespace Flax.Build
var dotnetLibPath = Utilities.NormalizePath(Path.GetDirectoryName(coreLibPaths[0])); var dotnetLibPath = Utilities.NormalizePath(Path.GetDirectoryName(coreLibPaths[0]));
Log.Info("Class library found in: " + dotnetLibPath); 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) // Build list of assemblies to process (use game assemblies as root to walk over used references from stdlib)
var assembliesPaths = new List<string>(); var assembliesPaths = new List<string>();
if (Configuration.SkipUnusedDotnetLibsPackaging) if (Configuration.SkipUnusedDotnetLibsPackaging)
@@ -354,6 +362,16 @@ namespace Flax.Build
assembliesPaths.AddRange(stdLibFiles); assembliesPaths.AddRange(stdLibFiles);
assembliesPaths.AddRange(inputFiles); assembliesPaths.AddRange(inputFiles);
} }
if (!wasm)
{
List<string> assembliesPaths2 = new();
foreach (var assemblyPath in assembliesPaths)
{
if (!assemblyPath.StartsWith(dotnetLibPath))
assembliesPaths2.Add(assemblyPath);
}
assembliesPaths = assembliesPaths2;
}
// Run compilation // Run compilation
bool failed = false, validCache = true, coreLibDirty = false; bool failed = false, validCache = true, coreLibDirty = false;
@@ -370,6 +388,7 @@ namespace Flax.Build
buildToolchain.CompileCSharp(ref options); buildToolchain.CompileCSharp(ref options);
platformToolsPath = options.PlatformToolsPath; platformToolsPath = options.PlatformToolsPath;
} }
//if (!wasm)
{ {
// Check if core library has been modified // Check if core library has been modified
var options = new Toolchain.CSharpOptions var options = new Toolchain.CSharpOptions
@@ -385,12 +404,39 @@ namespace Flax.Build
}; };
buildToolchain.CompileCSharp(ref options); buildToolchain.CompileCSharp(ref options);
coreLibDirty = File.GetLastWriteTime(options.InputFiles[0]) > File.GetLastWriteTime(options.OutputFiles[0]); coreLibDirty = File.GetLastWriteTime(options.InputFiles[0]) > File.GetLastWriteTime(options.OutputFiles[0]);
Log.Info("corelibdirty:" + coreLibDirty + ", " + options.OutputFiles[0]);
} }
if (!Directory.Exists(platformToolsPath)) if (!Directory.Exists(platformToolsPath))
throw new Exception("Missing platform tools " + platformToolsPath); throw new Exception("Missing platform tools " + platformToolsPath);
Log.Info("Platform tools found in: " + platformToolsPath); Log.Info("Platform tools found in: " + platformToolsPath);
// Workaround for unknown command "rm" when running on Windows
Utilities.WriteFileIfChanged(Path.Combine(aotAssembliesPath, "rm.bat"),
"""
@echo off
setlocal enabledelayedexpansion
set command=%*
set command=!command:~3!
del /F /Q /S %command%
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<string> outputStaticLibraryFiles = new ();
var compileAssembly = (string assemblyPath) => var compileAssembly = (string assemblyPath) =>
{ {
//if (!assemblyPath.Contains("Newtonsoft"))
// return;
// Determinate whether use debug information for that assembly // Determinate whether use debug information for that assembly
var useDebug = configuration != TargetConfiguration.Release; var useDebug = configuration != TargetConfiguration.Release;
if (!dotnetAotDebug && !inputFiles.Contains(assemblyPath)) if (!dotnetAotDebug && !inputFiles.Contains(assemblyPath))
@@ -411,6 +457,13 @@ namespace Flax.Build
EnableDebugSymbols = useDebug, EnableDebugSymbols = useDebug,
EnableToolDebug = dotnetAotDebug, EnableToolDebug = dotnetAotDebug,
}; };
if (true)
{
//if (Path.GetFileNameWithoutExtension(assemblyPath) == "System.Private.CoreLib")
}
buildToolchain.CompileCSharp(ref options); buildToolchain.CompileCSharp(ref options);
// Skip if output is already generated and is newer than a source assembly // Skip if output is already generated and is newer than a source assembly
@@ -452,8 +505,9 @@ namespace Flax.Build
// Copy AOT build products // Copy AOT build products
foreach (var outputFile in options.OutputFiles) foreach (var outputFile in options.OutputFiles)
{ {
outputStaticLibraryFiles.Add(outputFile);
// Skip if deployed file is already valid // 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)) if (!File.Exists(deployedFilePath) || File.GetLastWriteTime(outputFile) > File.GetLastWriteTime(deployedFilePath))
{ {
// Copy to the destination folder // Copy to the destination folder
@@ -461,7 +515,7 @@ namespace Flax.Build
if (useDebug && File.Exists(outputFile + ".pdb")) if (useDebug && File.Exists(outputFile + ".pdb"))
Utilities.FileCopy(outputFile + ".pdb", Path.Combine(dotnetOutputPath, Path.GetFileName(outputFile + ".pdb"))); Utilities.FileCopy(outputFile + ".pdb", Path.Combine(dotnetOutputPath, Path.GetFileName(outputFile + ".pdb")));
validCache = false; validCache = false;
} }*/
} }
} }
else else
@@ -470,6 +524,8 @@ namespace Flax.Build
Utilities.FileCopy(assemblyPath, Path.Combine(dotnetOutputPath, assemblyFileName), Utilities.CopyMode.OverrideIfNewer); Utilities.FileCopy(assemblyPath, Path.Combine(dotnetOutputPath, assemblyFileName), Utilities.CopyMode.OverrideIfNewer);
} }
}; };
Log.Info("AOT: " + string.Join(", ", assembliesPaths));
Log.Info("");
if (Configuration.MaxConcurrency > 1 && Configuration.ConcurrencyProcessorScale > 0.0f && !dotnetAotDebug) if (Configuration.MaxConcurrency > 1 && Configuration.ConcurrencyProcessorScale > 0.0f && !dotnetAotDebug)
{ {
// Multi-threaded // Multi-threaded
@@ -479,7 +535,14 @@ namespace Flax.Build
{ {
// Single-threaded // Single-threaded
foreach (var assemblyPath in assembliesPaths) foreach (var assemblyPath in assembliesPaths)
{
Log.Info("");
Log.Warning(" " + assemblyPath);
Log.Info("");
compileAssembly(assemblyPath); compileAssembly(assemblyPath);
if (failed)
break;
}
} }
if (failed) if (failed)
throw new Exception($"Failed to run AOT. See log ({Configuration.LogFile})."); throw new Exception($"Failed to run AOT. See log ({Configuration.LogFile}).");
@@ -504,6 +567,65 @@ namespace Flax.Build
throw new Exception("Mono AOT failed to link static libraries into a shared module"); 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 else
{ {

View File

@@ -148,6 +148,7 @@ namespace Flax.Build
TargetPlatform.Windows, TargetPlatform.Windows,
TargetPlatform.Linux, TargetPlatform.Linux,
TargetPlatform.Mac, TargetPlatform.Mac,
TargetPlatform.Web,
}; };
} }
} }
@@ -356,6 +357,9 @@ namespace Flax.Build
TryAddHostRuntime(TargetPlatform.Android, TargetArchitecture.ARM64, "android-arm64", "Runtime.Mono"); TryAddHostRuntime(TargetPlatform.Android, TargetArchitecture.ARM64, "android-arm64", "Runtime.Mono");
TryAddHostRuntime(TargetPlatform.iOS, TargetArchitecture.ARM, "ios-arm64", "Runtime.Mono"); TryAddHostRuntime(TargetPlatform.iOS, TargetArchitecture.ARM, "ios-arm64", "Runtime.Mono");
TryAddHostRuntime(TargetPlatform.iOS, TargetArchitecture.ARM64, "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 // Found
IsValid = true; IsValid = true;
@@ -410,10 +414,16 @@ namespace Flax.Build
case TargetPlatform.iOS: case TargetPlatform.iOS:
result = "ios"; result = "ios";
break; break;
case TargetPlatform.Web:
result = "browser";
break;
default: throw new InvalidPlatformException(platform); default: throw new InvalidPlatformException(platform);
} }
switch (architecture) switch (architecture)
{ {
case TargetArchitecture.x86 when platform == TargetPlatform.Web:
result += "-wasm";
break;
case TargetArchitecture.x86: case TargetArchitecture.x86:
result += "-x86"; result += "-x86";
break; break;

View File

@@ -276,6 +276,7 @@ namespace Flax.Build
case TargetPlatform.Linux: case TargetPlatform.Linux:
case TargetPlatform.iOS: case TargetPlatform.iOS:
case TargetPlatform.Mac: case TargetPlatform.Mac:
case TargetPlatform.Web:
// TODO: try to disable this on more platforms! (eg. LocalizationService::OnLocalizationChanged uses it) // TODO: try to disable this on more platforms! (eg. LocalizationService::OnLocalizationChanged uses it)
options.CompileEnv.EnableExceptions = true; options.CompileEnv.EnableExceptions = true;
break; break;

View File

@@ -296,8 +296,8 @@ namespace Flax.Build
public static bool WithCSharp(NativeCpp.BuildOptions options) public static bool WithCSharp(NativeCpp.BuildOptions options)
{ {
if (options.Platform.Target == TargetPlatform.Web) //if (options.Platform.Target == TargetPlatform.Web)
return false; // TODO: implement .NET for WebAssembly // return false; // TODO: implement .NET for WebAssembly
return UseCSharp || options.Target.IsEditor; return UseCSharp || options.Target.IsEditor;
} }

View File

@@ -24,6 +24,7 @@ namespace Flax.Deps.Dependencies
return new[] return new[]
{ {
TargetPlatform.Windows, TargetPlatform.Windows,
TargetPlatform.Web,
}; };
case TargetPlatform.Linux: case TargetPlatform.Linux:
return new[] return new[]
@@ -122,6 +123,7 @@ namespace Flax.Deps.Dependencies
} }
case TargetPlatform.Linux: case TargetPlatform.Linux:
case TargetPlatform.Mac: case TargetPlatform.Mac:
case TargetPlatform.Web:
{ {
var buildDir = Path.Combine(root, "build-" + architecture.ToString()); var buildDir = Path.Combine(root, "build-" + architecture.ToString());

View File

@@ -114,6 +114,7 @@ namespace Flax.Deps.Dependencies
case TargetPlatform.PS4: case TargetPlatform.PS4:
case TargetPlatform.PS5: case TargetPlatform.PS5:
case TargetPlatform.Switch: case TargetPlatform.Switch:
case TargetPlatform.Web:
runtimeFlavor = "Mono"; runtimeFlavor = "Mono";
setupVersion = true; setupVersion = true;
buildMonoAotCross = true; buildMonoAotCross = true;
@@ -128,6 +129,9 @@ namespace Flax.Deps.Dependencies
case TargetPlatform.Switch: case TargetPlatform.Switch:
os = "switch"; os = "switch";
break; break;
case TargetPlatform.Web:
os = "browser";
break;
default: throw new InvalidPlatformException(targetPlatform); 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"; 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";

View File

@@ -131,6 +131,7 @@ namespace Flax.Deps
TargetArchitecture.x86, TargetArchitecture.x86,
TargetArchitecture.x64, TargetArchitecture.x64,
TargetArchitecture.ARM64, TargetArchitecture.ARM64,
TargetArchitecture.x86,
}; };
case TargetPlatform.Linux: case TargetPlatform.Linux:
return new[] return new[]
@@ -487,6 +488,7 @@ namespace Flax.Deps
public static void RunCmake(string path, TargetPlatform platform, TargetArchitecture architecture, string customArgs = null, Dictionary<string, string> envVars = null) public static void RunCmake(string path, TargetPlatform platform, TargetArchitecture architecture, string customArgs = null, Dictionary<string, string> envVars = null)
{ {
string cmdLine; string cmdLine;
string cmakeBinary = "cmake";
switch (platform) switch (platform)
{ {
case TargetPlatform.Windows: case TargetPlatform.Windows:
@@ -567,6 +569,8 @@ namespace Flax.Deps
cmdLine = $"CMakeLists.txt -DCMAKE_TOOLCHAIN_FILE=\"{EmscriptenSdk.Instance.CMakeToolchainPath}\""; cmdLine = $"CMakeLists.txt -DCMAKE_TOOLCHAIN_FILE=\"{EmscriptenSdk.Instance.CMakeToolchainPath}\"";
if (BuildPlatform == TargetPlatform.Windows) if (BuildPlatform == TargetPlatform.Windows)
cmdLine += " -G \"Ninja\""; cmdLine += " -G \"Ninja\"";
//cmakeBinary = "emcmake.bat";
//cmdLine = "cmake CMakeLists.txt";
break; break;
} }
default: throw new InvalidPlatformException(platform); default: throw new InvalidPlatformException(platform);
@@ -575,7 +579,7 @@ namespace Flax.Deps
if (customArgs != null) if (customArgs != null)
cmdLine += " " + customArgs; cmdLine += " " + customArgs;
Utilities.Run("cmake", cmdLine, null, path, Utilities.RunOptions.DefaultTool, envVars); Utilities.Run(cmakeBinary, cmdLine, null, path, Utilities.RunOptions.DefaultTool, envVars);
} }
/// <summary> /// <summary>

View File

@@ -1,6 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved. // Copyright (c) Wojciech Figat. All rights reserved.
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -43,7 +44,7 @@ namespace Flax.Deps
if (Configuration.BuildArchitectures != null && Configuration.BuildArchitectures.Length != 0) if (Configuration.BuildArchitectures != null && Configuration.BuildArchitectures.Length != 0)
architectures = Configuration.BuildArchitectures; architectures = Configuration.BuildArchitectures;
architectures = architectures.Where(x => platforms.Any(y => Platform.GetPlatform(y, true)?.CanBuildArchitecture(x) ?? false)).ToArray(); architectures = architectures.Where(x => platforms.Any(y => Platform.GetPlatform(y, true)?.CanBuildArchitecture(x) ?? false)).ToArray();
Log.Verbose($"Building deps for platforms {string.Join(',', platforms)}, {string.Join(',', architectures)}:"); Log.Verbose($"Building deps for platforms [{string.Join(", ", platforms)}] with architectures [{string.Join(", ", architectures)}]:");
foreach (var platform in platforms) foreach (var platform in platforms)
{ {
foreach (var architecture in architectures) foreach (var architecture in architectures)
@@ -59,49 +60,63 @@ namespace Flax.Deps
var dependencies = Builder.BuildTypes.Where(x => x.IsSubclassOf(typeof(Dependency))).Select(Activator.CreateInstance).Cast<Dependency>().ToArray(); var dependencies = Builder.BuildTypes.Where(x => x.IsSubclassOf(typeof(Dependency))).Select(Activator.CreateInstance).Cast<Dependency>().ToArray();
if (dependencies.Length == 0) if (dependencies.Length == 0)
Log.Warning("No dependencies found!"); Log.Warning("No dependencies found!");
List<Dependency> failedDependencies = new();
for (var i = 0; i < dependencies.Length; i++) for (var i = 0; i < dependencies.Length; i++)
{ {
var dependency = dependencies[i]; var dependency = dependencies[i];
var name = dependency.GetType().Name; try
if (depsToBuild.Length > 0 || !dependency.BuildByDefault)
{ {
if (!depsToBuild.Contains(name.ToLower())) var name = dependency.GetType().Name;
if (depsToBuild.Length > 0 || !dependency.BuildByDefault)
{
if (!depsToBuild.Contains(name.ToLower()))
{
Log.Info(string.Format("Skipping {0} ({1}/{2})", name, i + 1, dependencies.Length));
Log.Verbose("Not selected for build.");
continue;
}
}
options.Platforms = platforms.Intersect(dependency.Platforms).ToArray();
if (options.Platforms.Length == 0)
{ {
Log.Info(string.Format("Skipping {0} ({1}/{2})", name, i + 1, dependencies.Length)); Log.Info(string.Format("Skipping {0} ({1}/{2})", name, i + 1, dependencies.Length));
Log.Verbose("Not selected for build."); Log.Verbose("Not used on any of the build platforms.");
continue; continue;
} }
}
options.Platforms = platforms.Intersect(dependency.Platforms).ToArray(); options.Architectures = architectures.Intersect(dependency.Architectures).ToArray();
if (options.Platforms.Length == 0) if (options.Architectures.Length == 0)
{
Log.Info(string.Format("Skipping {0} ({1}/{2})", name, i + 1, dependencies.Length));
Log.Verbose("Architecture not used on any of the build platforms.");
continue;
}
Log.Info(string.Format("Building {0} ({1}/{2})", name, i + 1, dependencies.Length));
options.IntermediateFolder = Path.Combine(Environment.CurrentDirectory, "Cache", "Intermediate", "Deps", name).Replace('\\', '/');
if (!Configuration.ReBuildDeps && Directory.Exists(options.IntermediateFolder))
{
Log.Verbose(string.Format("{0} is up-to-date. Skipping build.", name));
continue;
}
var forceEmpty = false; //Configuration.ReBuildDeps;
Dependency.SetupDirectory(options.IntermediateFolder, forceEmpty);
dependency.Build(options);
}
catch (Exception e)
{ {
Log.Info(string.Format("Skipping {0} ({1}/{2})", name, i + 1, dependencies.Length)); failedDependencies.Add(dependency);
Log.Verbose("Not used on any of the build platforms."); Log.Error(e.ToString());
continue;
} }
}
options.Architectures = architectures.Intersect(dependency.Architectures).ToArray(); if (failedDependencies.Count > 0)
if (options.Architectures.Length == 0) {
{ Log.Error("Failed to build the following dependencies: " + string.Join(", ", failedDependencies.Select(x => x.GetType().Name)));
Log.Info(string.Format("Skipping {0} ({1}/{2})", name, i + 1, dependencies.Length));
Log.Verbose("Architecture not used on any of the build platforms.");
continue;
}
Log.Info(string.Format("Building {0} ({1}/{2})", name, i + 1, dependencies.Length));
options.IntermediateFolder = Path.Combine(Environment.CurrentDirectory, "Cache", "Intermediate", "Deps", name).Replace('\\', '/');
if (!Configuration.ReBuildDeps && Directory.Exists(options.IntermediateFolder))
{
Log.Verbose(string.Format("{0} is up-to-date. Skipping build.", name));
continue;
}
var forceEmpty = false; //Configuration.ReBuildDeps;
Dependency.SetupDirectory(options.IntermediateFolder, forceEmpty);
dependency.Build(options);
} }
Log.Info("Done!"); Log.Info("Done!");

View File

@@ -70,7 +70,7 @@ namespace Flax.Build.Platforms
versionStr = versionStr.Substring(1, versionStr.Length - 2); versionStr = versionStr.Substring(1, versionStr.Length - 2);
Version = new Version(versionStr); Version = new Version(versionStr);
var minVersion = new Version(4, 0); var minVersion = new Version(3, 1);
if (Version < minVersion) if (Version < minVersion)
{ {
Log.Error(string.Format("Unsupported Emscripten SDK version {0}. Minimum supported is {1}.", Version, minVersion)); Log.Error(string.Format("Unsupported Emscripten SDK version {0}. Minimum supported is {1}.", Version, minVersion));

View File

@@ -32,7 +32,7 @@ namespace Flax.Build.Platforms
public override string ExecutableFileExtension => ".html"; public override string ExecutableFileExtension => ".html";
/// <inheritdoc /> /// <inheritdoc />
public override string SharedLibraryFileExtension => ".wasm"; public override string SharedLibraryFileExtension => ".so";//".wasm";
/// <inheritdoc /> /// <inheritdoc />
public override string StaticLibraryFileExtension => ".a"; public override string StaticLibraryFileExtension => ".a";

View File

@@ -100,6 +100,8 @@ namespace Flax.Build.Platforms
private void AddSharedArgs(List<string> args, BuildOptions options, bool debugInformation, bool optimization) private void AddSharedArgs(List<string> args, BuildOptions options, bool debugInformation, bool optimization)
{ {
//args.Add("-pthread");
if (debugInformation) if (debugInformation)
args.Add("-g2"); args.Add("-g2");
else else
@@ -153,7 +155,7 @@ namespace Flax.Build.Platforms
if (options.LinkEnv.LinkTimeCodeGeneration) if (options.LinkEnv.LinkTimeCodeGeneration)
args.Add("-flto"); args.Add("-flto");
if (options.LinkEnv.Output == LinkerOutput.SharedLibrary) //if (options.LinkEnv.Output == LinkerOutput.SharedLibrary)
args.Add("-fPIC"); args.Add("-fPIC");
var sanitizers = options.CompileEnv.Sanitizers; var sanitizers = options.CompileEnv.Sanitizers;
@@ -179,8 +181,8 @@ namespace Flax.Build.Platforms
AddSharedArgs(commonArgs, options, options.CompileEnv.DebugInformation, options.CompileEnv.Optimization); AddSharedArgs(commonArgs, options, options.CompileEnv.DebugInformation, options.CompileEnv.Optimization);
// Hack to pull SDL3 port via emcc // Hack to pull SDL3 port via emcc
if (options.CompileEnv.PreprocessorDefinitions.Contains("PLATFORM_SDL")) //if (options.CompileEnv.PreprocessorDefinitions.Contains("PLATFORM_SDL"))
commonArgs.Add("--use-port=sdl3"); // commonArgs.Add("--use-port=sdl3");
} }
// Add preprocessor definitions // Add preprocessor definitions
@@ -260,6 +262,322 @@ namespace Flax.Build.Platforms
return output; 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.MonoLink:
{
// Setup arguments
var args = new List<string>();
//args.AddRange(options.LinkEnv.CustomArgs);
{
args.Add(string.Format("-o \"{0}\"", options.OutputFiles[0].Replace('\\', '/')));
//AddSharedArgs(args, options, false, false);
// Setup memory
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("-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("-sLZ4");
// https://emscripten.org/docs/compiling/Dynamic-Linking.html#dynamic-linking
// TODO: use -sMAIN_MODULE=2 and -sSIDE_MODULE=2 to strip unused code (mark public APIs with EMSCRIPTEN_KEEPALIVE)
/*if (options.LinkEnv.Output == LinkerOutput.Executable)
{
args.Add("-sMAIN_MODULE");
args.Add("-sEXPORT_ALL");
}
else*/
{
args.Add("-sSIDE_MODULE");
}
}
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");
// Input libraries
var libraryPaths = new HashSet<string>();
var dynamicLibExt = Platform.SharedLibraryFileExtension;
var executableExt = Platform.ExecutableFileExtension;
foreach (var library in options.InputFiles)
{
/*var dir = Path.GetDirectoryName(library);
var ext = Path.GetExtension(library);
if (library.StartsWith("--use-port="))
{
// Ports (https://emscripten.org/docs/compiling/Building-Projects.html#emscripten-ports)
args.Add(library);
}
else if (string.IsNullOrEmpty(dir))
{
args.Add(string.Format("\"-l{0}\"", library));
}
else if (ext == executableExt)
{
// Skip executable
}
else if (ext == dynamicLibExt)
{
// Link against dynamic library
//task.PrerequisiteFiles.Add(library);
libraryPaths.Add(dir);
args.Add(string.Format("\"-l{0}\"", GetLibName(library)));
}
else
{
//task.PrerequisiteFiles.Add(library);
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);
}
// Input files (link static libraries last)
/*task.PrerequisiteFiles.AddRange(options.LinkEnv.InputFiles);
foreach (var file in options.LinkEnv.InputFiles.Where(x => !x.EndsWith(".a")).Concat(options.LinkEnv.InputFiles.Where(x => x.EndsWith(".a"))))
{
args.Add(string.Format("\"{0}\"", file.Replace('\\', '/')));
}
// Additional lib paths
libraryPaths.AddRange(options.LinkEnv.LibraryPaths);
foreach (var path in libraryPaths)
{
args.Add(string.Format("-L\"{0}\"", path.Replace('\\', '/')));
}*/
args.Add("-Wl,--end-group");
// Use a response file (it can contain any commands that you would specify on the command line)
bool useResponseFile = true;
string responseFile = null;
if (useResponseFile)
{
responseFile = Path.Combine(options.AssembliesPath, Path.GetFileName(options.OutputFiles[0]) + ".response");
//task.PrerequisiteFiles.Add(responseFile);
Utilities.WriteFileIfChanged(responseFile, string.Join(Environment.NewLine, args));
args.Clear();
args.Add(string.Format("@\"{0}\"", responseFile));
}
//task.WorkingDirectory = options.WorkingDirectory;
//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, options.PlatformToolsPath, Utilities.RunOptions.AppMustExist | Utilities.RunOptions.ConsoleLogOutput);
if (result != 0)
return true;
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 llvmPath = "\"" + Path.Combine(EmscriptenSdk.Instance.EmscriptenPath, "bin") + "\"";
var monoAotMode = "full";
if (useLLVM)
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";
//aotCompilerArgs += $" --aot-path=\"{inputFileFolder}\"";
//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<string, string>();
envVars["MONO_PATH"] = options.ClassLibraryPath.Replace('/', Path.DirectorySeparatorChar) + Path.PathSeparator + options.AssembliesPath.Replace('/', Path.DirectorySeparatorChar);
Log.Info("MONO_PATH: " + envVars["MONO_PATH"]);
if (options.EnableToolDebug)
{
envVars["MONO_LOG_LEVEL"] = "debug";
}
//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<string>();
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
/// <inheritdoc />
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<string, string>();
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) private Task CreateBinary(TaskGraph graph, BuildOptions options, string outputFilePath)
{ {
var task = graph.Add<LinkTask>(); var task = graph.Add<LinkTask>();
@@ -297,6 +615,8 @@ namespace Flax.Build.Platforms
} }
} }
args.Add("-Wl,--allow-multiple-definition"); // Multiple pthread-related definitions in dotnet runtime
args.Add("-Wl,--start-group"); args.Add("-Wl,--start-group");
// Input libraries // Input libraries
@@ -331,6 +651,7 @@ namespace Flax.Build.Platforms
{ {
task.PrerequisiteFiles.Add(library); task.PrerequisiteFiles.Add(library);
args.Add(string.Format("\"-l{0}\"", GetLibName(library))); args.Add(string.Format("\"-l{0}\"", GetLibName(library)));
libraryPaths.Add(dir); // FIXME
} }
} }

View File

@@ -76,8 +76,8 @@ namespace Flax.Build.Platforms
public override bool CanBuildArchitecture(TargetArchitecture targetArchitecture) public override bool CanBuildArchitecture(TargetArchitecture targetArchitecture)
{ {
// Prevent generating configuration data for Windows x86 (deprecated) // Prevent generating configuration data for Windows x86 (deprecated)
if (targetArchitecture == TargetArchitecture.x86) //if (targetArchitecture == TargetArchitecture.x86)
return false; // return false;
// Check if we have a compiler for this architecture // Check if we have a compiler for this architecture
var toolsets = GetToolsets(); var toolsets = GetToolsets();

View File

@@ -500,6 +500,9 @@ namespace Flax.Build.Platforms
// List Include Files // List Include Files
//commonArgs.Add("/showIncludes"); //commonArgs.Add("/showIncludes");
commonArgs.Add("/permissive-");
commonArgs.Add("/Zc:externC-");
// Code Analysis // Code Analysis
commonArgs.Add("/analyze-"); commonArgs.Add("/analyze-");

View File

@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Reflection;
using System.Threading; using System.Threading;
using Flax.Deploy; using Flax.Deploy;
using Flax.Deps; using Flax.Deps;
@@ -173,6 +174,10 @@ namespace Flax.Build
} }
catch (Exception ex) 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 // Ignore exception logging for build errors
if (!(ex is BuildException)) if (!(ex is BuildException))
Log.Exception(ex); Log.Exception(ex);