From 30e825db7513dc492b4809386c2eba5621189b02 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 21 Mar 2023 22:49:09 +0100 Subject: [PATCH] Add dotnet7 for Android (wip) --- Source/Editor/Cooker/CookingData.h | 5 + Source/Editor/Cooker/GameCooker.cpp | 65 +++++++++ .../Cooker/Steps/CompileScriptsStep.cpp | 63 +-------- Source/Editor/Cooker/Steps/DeployDataStep.cpp | 133 +++++++++++------- Source/Engine/Scripting/DotNet/CoreCLR.cpp | 18 +++ Source/Engine/Scripting/Scripting.Build.cs | 4 +- Source/ThirdParty/nethost/nethost.Build.cs | 19 ++- .../Flax.Build/Build/DotNet/DotNetSdk.cs | 40 +++++- Source/Tools/Flax.Build/Build/Sdk.cs | 21 ++- Source/Tools/Flax.Build/CommandLine.cs | 10 ++ .../Tools/Flax.Build/CommandLineAttribute.cs | 2 +- Source/Tools/Flax.Build/Configuration.cs | 20 ++- .../Flax.Build/Deps/Dependencies/nethost.cs | 59 ++++++-- Source/Tools/Flax.Build/Deps/Dependency.cs | 8 ++ Source/Tools/Flax.Build/Log.cs | 16 ++- Source/Tools/Flax.Build/Program.cs | 10 +- 16 files changed, 348 insertions(+), 145 deletions(-) diff --git a/Source/Editor/Cooker/CookingData.h b/Source/Editor/Cooker/CookingData.h index 0520f1b63..e0422e679 100644 --- a/Source/Editor/Cooker/CookingData.h +++ b/Source/Editor/Cooker/CookingData.h @@ -319,6 +319,11 @@ public: /// String GetPlatformBinariesRoot() const; + /// + /// Gets the name of the platform and architecture for the current BuildPlatform. + /// + void GetBuildPlatformName(const Char*& platform, const Char*& architecture) const; + public: /// diff --git a/Source/Editor/Cooker/GameCooker.cpp b/Source/Editor/Cooker/GameCooker.cpp index 791b205e2..79594c8da 100644 --- a/Source/Editor/Cooker/GameCooker.cpp +++ b/Source/Editor/Cooker/GameCooker.cpp @@ -219,6 +219,71 @@ String CookingData::GetPlatformBinariesRoot() const return Globals::StartupFolder / TEXT("Source/Platforms") / Tools->GetName() / TEXT("Binaries"); } +void CookingData::GetBuildPlatformName(const Char*& platform, const Char*& architecture) const +{ + switch (Platform) + { + case BuildPlatform::Windows32: + platform = TEXT("Windows"); + architecture = TEXT("x86"); + break; + case BuildPlatform::Windows64: + platform = TEXT("Windows"); + architecture = TEXT("x64"); + break; + case BuildPlatform::UWPx86: + platform = TEXT("UWP"); + architecture = TEXT("x86"); + break; + case BuildPlatform::UWPx64: + platform = TEXT("UWP"); + architecture = TEXT("x64"); + break; + case BuildPlatform::XboxOne: + platform = TEXT("XboxOne"); + architecture = TEXT("x64"); + break; + case BuildPlatform::LinuxX64: + platform = TEXT("Linux"); + architecture = TEXT("x64"); + break; + case BuildPlatform::PS4: + platform = TEXT("PS4"); + architecture = TEXT("x64"); + break; + case BuildPlatform::XboxScarlett: + platform = TEXT("XboxScarlett"); + architecture = TEXT("x64"); + break; + case BuildPlatform::AndroidARM64: + platform = TEXT("Android"); + architecture = TEXT("ARM64"); + break; + case BuildPlatform::Switch: + platform = TEXT("Switch"); + architecture = TEXT("ARM64"); + break; + case BuildPlatform::PS5: + platform = TEXT("PS5"); + architecture = TEXT("x64"); + break; + case BuildPlatform::MacOSx64: + platform = TEXT("Mac"); + architecture = TEXT("x64"); + break; + case BuildPlatform::MacOSARM64: + platform = TEXT("Mac"); + architecture = TEXT("ARM64"); + break; + case BuildPlatform::iOSARM64: + platform = TEXT("iOS"); + architecture = TEXT("ARM64"); + break; + default: + LOG(Fatal, "Unknown or unsupported build platform."); + } +} + void CookingData::StepProgress(const String& info, const float stepProgress) const { const float singleStepProgress = 1.0f / (StepsCount + 1); diff --git a/Source/Editor/Cooker/Steps/CompileScriptsStep.cpp b/Source/Editor/Cooker/Steps/CompileScriptsStep.cpp index baa628486..c6b1a824f 100644 --- a/Source/Editor/Cooker/Steps/CompileScriptsStep.cpp +++ b/Source/Editor/Cooker/Steps/CompileScriptsStep.cpp @@ -154,68 +154,7 @@ bool CompileScriptsStep::Perform(CookingData& data) String target = project->GameTarget; StringView workingDir; const Char *platform, *architecture, *configuration = ::ToString(data.Configuration); - switch (data.Platform) - { - case BuildPlatform::Windows32: - platform = TEXT("Windows"); - architecture = TEXT("x86"); - break; - case BuildPlatform::Windows64: - platform = TEXT("Windows"); - architecture = TEXT("x64"); - break; - case BuildPlatform::UWPx86: - platform = TEXT("UWP"); - architecture = TEXT("x86"); - break; - case BuildPlatform::UWPx64: - platform = TEXT("UWP"); - architecture = TEXT("x64"); - break; - case BuildPlatform::XboxOne: - platform = TEXT("XboxOne"); - architecture = TEXT("x64"); - break; - case BuildPlatform::LinuxX64: - platform = TEXT("Linux"); - architecture = TEXT("x64"); - break; - case BuildPlatform::PS4: - platform = TEXT("PS4"); - architecture = TEXT("x64"); - break; - case BuildPlatform::XboxScarlett: - platform = TEXT("XboxScarlett"); - architecture = TEXT("x64"); - break; - case BuildPlatform::AndroidARM64: - platform = TEXT("Android"); - architecture = TEXT("ARM64"); - break; - case BuildPlatform::Switch: - platform = TEXT("Switch"); - architecture = TEXT("ARM64"); - break; - case BuildPlatform::PS5: - platform = TEXT("PS5"); - architecture = TEXT("x64"); - break; - case BuildPlatform::MacOSx64: - platform = TEXT("Mac"); - architecture = TEXT("x64"); - break; - case BuildPlatform::MacOSARM64: - platform = TEXT("Mac"); - architecture = TEXT("ARM64"); - break; - case BuildPlatform::iOSARM64: - platform = TEXT("iOS"); - architecture = TEXT("ARM64"); - break; - default: - LOG(Error, "Unknown or unsupported build platform."); - return true; - } + data.GetBuildPlatformName(platform, architecture); String targetBuildInfo = project->ProjectFolderPath / TEXT("Binaries") / target / platform / architecture / configuration / target + TEXT(".Build.json"); if (target.IsEmpty()) { diff --git a/Source/Editor/Cooker/Steps/DeployDataStep.cpp b/Source/Editor/Cooker/Steps/DeployDataStep.cpp index 9187ec29b..c8e547764 100644 --- a/Source/Editor/Cooker/Steps/DeployDataStep.cpp +++ b/Source/Editor/Cooker/Steps/DeployDataStep.cpp @@ -68,6 +68,7 @@ bool DeployDataStep::Perform(CookingData& data) if (FileSystem::DirectoryExists(srcDotnet)) { // Use prebuilt .Net installation for that platform + LOG(Info, "Using .Net Runtime {} at {}", data.Tools->GetName(), srcDotnet); if (FileSystem::CopyDirectory(dstDotnet, srcDotnet, true)) { data.Error(TEXT("Failed to copy .Net runtime data files.")); @@ -91,61 +92,95 @@ bool DeployDataStep::Perform(CookingData& data) canUseSystemDotnet = PLATFORM_TYPE == PlatformType::Mac; break; } - if (!canUseSystemDotnet) + if (canUseSystemDotnet) { - data.Error(TEXT("Missing .Net files for a target platform.")); - return true; - } + // Ask Flax.Build to provide .Net SDK location for the current platform + String sdks; + bool failed = ScriptsBuilder::RunBuildTool(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs"), data.CacheDirectory); + failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks); + int32 idx = sdks.Find(TEXT("] DotNetSdk, "), StringSearchCase::CaseSensitive); + if (idx != -1) + { + idx = sdks.Find(TEXT(", "), StringSearchCase::CaseSensitive, idx + 14); + idx += 2; + int32 end = sdks.Find(TEXT("\n"), StringSearchCase::CaseSensitive, idx); + if (sdks[end] == '\r') + end--; + srcDotnet = String(sdks.Get() + idx, end - idx).TrimTrailing(); + } + if (failed || !FileSystem::DirectoryExists(srcDotnet)) + { + data.Error(TEXT("Failed to get .Net SDK location for a current platform.")); + return true; + } - // Ask Flax.Build to provide .Net SDK location for current platform (assuming there are no prebuilt dotnet files) - String sdks; - bool failed = ScriptsBuilder::RunBuildTool(TEXT("-log -printSDKs -logfile=SDKs.txt"), data.CacheDirectory); - failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks); - int32 idx = sdks.Find(TEXT("] DotNetSdk, "), StringSearchCase::CaseSensitive); - if (idx != -1) - { - idx = sdks.Find(TEXT(", "), StringSearchCase::CaseSensitive, idx + 14); - idx += 2; - int32 end = sdks.Find(TEXT("\n"), StringSearchCase::CaseSensitive, idx); - if (sdks[end] == '\r') - end--; - srcDotnet = String(sdks.Get() + idx, end - idx).TrimTrailing(); - } - if (failed || !FileSystem::DirectoryExists(srcDotnet)) - { - data.Error(TEXT("Failed to get .Net SDK location for a current platform.")); - return true; - } + // Select version to use + Array versions; + FileSystem::GetChildDirectories(versions, srcDotnet / TEXT("host/fxr")); + if (versions.Count() == 0) + { + data.Error(TEXT("Failed to get .Net SDK location for a current platform.")); + return true; + } + for (String& version : versions) + { + version = StringUtils::GetFileName(version); + if (!version.StartsWith(TEXT("7."))) + version.Clear(); + } + Sorting::QuickSort(versions.Get(), versions.Count()); + const String version = versions.Last(); + LOG(Info, "Using .Net Runtime {} at {}", version, srcDotnet); - // Select version to use - Array versions; - FileSystem::GetChildDirectories(versions, srcDotnet / TEXT("host/fxr")); - if (versions.Count() == 0) - { - data.Error(TEXT("Failed to get .Net SDK location for a current platform.")); - return true; + // Deploy runtime files + FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), srcDotnet / TEXT("LICENSE.txt")); + FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), srcDotnet / TEXT("LICENSE.TXT")); + FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), srcDotnet / TEXT("ThirdPartyNotices.txt")); + FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), srcDotnet / TEXT("THIRD-PARTY-NOTICES.TXT")); + failed |= FileSystem::CopyDirectory(dstDotnet / TEXT("host/fxr") / version, srcDotnet / TEXT("host/fxr") / version, true); + failed |= FileSystem::CopyDirectory(dstDotnet / TEXT("shared/Microsoft.NETCore.App") / version, srcDotnet / TEXT("shared/Microsoft.NETCore.App") / version, true); + if (failed) + { + data.Error(TEXT("Failed to copy .Net runtime data files.")); + return true; + } } - for (String& version : versions) + else { - version = StringUtils::GetFileName(version); - if (!version.StartsWith(TEXT("7."))) - version.Clear(); - } - Sorting::QuickSort(versions.Get(), versions.Count()); - const String version = versions.Last(); - LOG(Info, "Using .Net Runtime {} at {}", version, srcDotnet); + // Ask Flax.Build to provide .Net Host Runtime location for the target platform + String sdks; + const Char* platformName, *archName; + data.GetBuildPlatformName(platformName, archName); + String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={}"), platformName, archName); + bool failed = ScriptsBuilder::RunBuildTool(args, data.CacheDirectory); + failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks); + Array parts; + sdks.Split(',', parts); + failed |= parts.Count() != 3; + if (!failed) + { + srcDotnet = parts[2].TrimTrailing(); + } + if (failed || !FileSystem::DirectoryExists(srcDotnet)) + { + data.Error(TEXT("Failed to get .Net SDK location for a current platform.")); + return true; + } + LOG(Info, "Using .Net Runtime {} at {}", TEXT("Host"), srcDotnet); - // Deploy runtime files - FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), srcDotnet / TEXT("LICENSE.txt")); - FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), srcDotnet / TEXT("LICENSE.TXT")); - FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), srcDotnet / TEXT("ThirdPartyNotices.txt")); - FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), srcDotnet / TEXT("THIRD-PARTY-NOTICES.TXT")); - failed |= FileSystem::CopyDirectory(dstDotnet / TEXT("host/fxr") / version, srcDotnet / TEXT("host/fxr") / version, true); - failed |= FileSystem::CopyDirectory(dstDotnet / TEXT("shared/Microsoft.NETCore.App") / version, srcDotnet / TEXT("shared/Microsoft.NETCore.App") / version, true); - if (failed) - { - data.Error(TEXT("Failed to copy .Net runtime data files.")); - return true; + // Deploy runtime files + const String packFolder = srcDotnet / TEXT("../../../"); + FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), packFolder / TEXT("LICENSE.txt")); + FileSystem::CopyFile(dstDotnet / TEXT("LICENSE.TXT"), packFolder / TEXT("LICENSE.TXT")); + FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), packFolder / TEXT("ThirdPartyNotices.txt")); + FileSystem::CopyFile(dstDotnet / TEXT("THIRD-PARTY-NOTICES.TXT"), packFolder / TEXT("THIRD-PARTY-NOTICES.TXT")); + failed |= FileSystem::CopyDirectory(dstDotnet / TEXT("shared/Microsoft.NETCore.App"), srcDotnet / TEXT("../lib/net7.0"), true); + failed |= FileSystem::CopyFile(dstDotnet / TEXT("shared/Microsoft.NETCore.App") / TEXT("System.Private.CoreLib.dll"), srcDotnet / TEXT("System.Private.CoreLib.dll")); + if (failed) + { + data.Error(TEXT("Failed to copy .Net runtime data files.")); + return true; + } } } } diff --git a/Source/Engine/Scripting/DotNet/CoreCLR.cpp b/Source/Engine/Scripting/DotNet/CoreCLR.cpp index eae7e9e20..83fcf25e6 100644 --- a/Source/Engine/Scripting/DotNet/CoreCLR.cpp +++ b/Source/Engine/Scripting/DotNet/CoreCLR.cpp @@ -10,9 +10,16 @@ #include "Engine/Core/Collections/Dictionary.h" #include "Engine/Debug/DebugLog.h" #include "Engine/Engine/Globals.h" +#if DOTNET_HOST_CORECRL #include #include #include +#elif DOTNET_HOST_MONO +#include +typedef char char_t; +#else +#error "Unknown .NET runtime host." +#endif #if PLATFORM_WINDOWS #include #undef SetEnvironmentVariable @@ -22,6 +29,7 @@ static Dictionary CachedFunctions; static const char_t* NativeInteropTypeName = FLAX_CORECLR_TEXT("FlaxEngine.NativeInterop, FlaxEngine.CSharp"); +#if DOTNET_HOST_CORECRL hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config; hostfxr_initialize_for_dotnet_command_line_fn hostfxr_initialize_for_dotnet_command_line; hostfxr_get_runtime_delegate_fn hostfxr_get_runtime_delegate; @@ -31,9 +39,11 @@ get_function_pointer_fn get_function_pointer; hostfxr_set_error_writer_fn hostfxr_set_error_writer; hostfxr_get_dotnet_environment_info_result_fn hostfxr_get_dotnet_environment_info_result; hostfxr_run_app_fn hostfxr_run_app; +#endif bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath) { +#if DOTNET_HOST_CORECRL const FLAX_CORECLR_STRING& library_path = FLAX_CORECLR_STRING(libraryPath); // Get path to hostfxr library @@ -128,6 +138,10 @@ bool CoreCLR::InitHostfxr(const String& configPath, const String& libraryPath) hostfxr_close(handle); get_function_pointer = (get_function_pointer_fn)pget_function_pointer; +#elif DOTNET_HOST_MONO + LOG(Fatal, "TODO: init mono hosting runtime"); +#endif + return false; } @@ -137,8 +151,12 @@ void* CoreCLR::GetStaticMethodPointer(const String& methodName) if (CachedFunctions.TryGet(methodName, fun)) return fun; +#if DOTNET_HOST_CORECRL int rc = get_function_pointer(NativeInteropTypeName, FLAX_CORECLR_STRING(methodName).Get(), UNMANAGEDCALLERSONLY_METHOD, nullptr, nullptr, &fun); if (rc != 0) +#else + int rc = -1; +#endif LOG(Fatal, "Failed to get unmanaged function pointer for method {0}: 0x{1:x}", methodName.Get(), (unsigned int)rc); CachedFunctions.Add(methodName, fun); diff --git a/Source/Engine/Scripting/Scripting.Build.cs b/Source/Engine/Scripting/Scripting.Build.cs index 2fd4b54df..c3c98599d 100644 --- a/Source/Engine/Scripting/Scripting.Build.cs +++ b/Source/Engine/Scripting/Scripting.Build.cs @@ -17,7 +17,9 @@ public class Scripting : EngineModule { if (EngineConfiguration.WithDotNet(options)) { - options.PublicDependencies.Add("nethost"); + options.PrivateDependencies.Add("nethost"); + options.ScriptingAPI.Defines.Add("USE_NETCORE"); + options.PublicDefinitions.Add("USE_NETCORE"); if (options.Target is EngineTarget engineTarget && engineTarget.UseSeparateMainExecutable(options)) { diff --git a/Source/ThirdParty/nethost/nethost.Build.cs b/Source/ThirdParty/nethost/nethost.Build.cs index e15793e7f..6ad833e1e 100644 --- a/Source/ThirdParty/nethost/nethost.Build.cs +++ b/Source/ThirdParty/nethost/nethost.Build.cs @@ -41,6 +41,7 @@ public class nethost : ThirdPartyModule } // Setup build configuration + bool useMonoHost = false; switch (options.Platform.Target) { case TargetPlatform.Windows: @@ -51,7 +52,6 @@ public class nethost : ThirdPartyModule options.DependencyFiles.Add(Path.Combine(hostRuntimePath, "nethost.dll")); break; case TargetPlatform.Linux: - case TargetPlatform.Android: options.OutputFiles.Add(Path.Combine(hostRuntimePath, "libnethost.a")); options.DependencyFiles.Add(Path.Combine(hostRuntimePath, "libnethost.so")); break; @@ -65,11 +65,24 @@ public class nethost : ThirdPartyModule options.OutputFiles.Add(Path.Combine(hostRuntimePath, "libnethost.a")); //options.OutputFiles.Add(Path.Combine(hostRuntimePath, "libhostfxr.a")); break; + case TargetPlatform.Android: + useMonoHost = true; + break; default: throw new InvalidPlatformException(options.Platform.Target); } - options.PublicIncludePaths.Add(hostRuntimePath); - options.ScriptingAPI.Defines.Add("USE_NETCORE"); options.DependencyFiles.Add(Path.Combine(FolderPath, "FlaxEngine.CSharp.runtimeconfig.json")); + if (useMonoHost) + { + // Use Mono for runtime hosting + options.PublicDefinitions.Add("DOTNET_HOST_MONO"); + options.PublicIncludePaths.Add(Path.Combine(hostRuntimePath, "include", "mono-2.0")); + } + else + { + // Use CoreCRL for runtime hosting + options.PublicDefinitions.Add("DOTNET_HOST_CORECRL"); + options.PublicIncludePaths.Add(hostRuntimePath); + } } } diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs index e97bd3875..5ced97864 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs @@ -8,6 +8,19 @@ using Microsoft.Win32; namespace Flax.Build { + partial class Configuration + { + /// + /// Prints all .NET Runtimes found on system (use plaform/arch switches to filter results). + /// + [CommandLine("printDotNetRuntime", "Prints all .NET Runtimes found on system (use plaform/arch switches to filter results).")] + public static void PrintDotNetRuntime() + { + Log.Info("Printing .NET Runtimes..."); + DotNetSdk.Instance.PrintRuntimes(); + } + } + /// /// The DotNet SDK. /// @@ -169,6 +182,7 @@ namespace Flax.Build TryAddHostRuntime(TargetPlatform.Windows, TargetArchitecture.ARM64, "win-arm64"); TryAddHostRuntime(TargetPlatform.Mac, TargetArchitecture.x64, "osx-x64"); TryAddHostRuntime(TargetPlatform.Mac, TargetArchitecture.ARM64, "osx-arm64"); + TryAddHostRuntime(TargetPlatform.Android, TargetArchitecture.ARM64, "android-arm64", "Runtime.Mono"); // Found IsValid = true; @@ -177,6 +191,25 @@ namespace Flax.Build Log.Verbose($" - Host Runtime for {e.Key.Key} {e.Key.Value}"); } + /// + /// Prints the .NET runtimes hosts. + /// + public void PrintRuntimes() + { + foreach (var e in _hostRuntimes) + { + // Filter with input commandline + TargetPlatform[] platforms = Configuration.BuildPlatforms; + if (platforms != null && !platforms.Contains(e.Key.Key)) + continue; + TargetArchitecture[] architectures = Configuration.BuildArchitectures; + if (architectures != null && !architectures.Contains(e.Key.Value)) + continue; + + Log.Message($"{e.Key.Key}, {e.Key.Value}, {e.Value}"); + } + } + /// /// Gets the path to runtime host contents folder for a given target platform and architecture. /// In format: <RootPath>/packs/Microsoft.NETCore.App.Host.<os>/<VersionName>/runtimes/<os>-<arch>/native @@ -198,12 +231,17 @@ namespace Flax.Build _hostRuntimes[new KeyValuePair(platform, arch)] = path; } - private bool TryAddHostRuntime(TargetPlatform platform, TargetArchitecture arch, string rid) + private bool TryAddHostRuntime(TargetPlatform platform, TargetArchitecture arch, string rid, string runtimeName = null) { if (string.IsNullOrEmpty(rid)) return false; var path = Path.Combine(RootPath, $"packs/Microsoft.NETCore.App.Host.{rid}/{RuntimeVersionName}/runtimes/{rid}/native"); var exists = Directory.Exists(path); + if (!exists && runtimeName != null) + { + path = Path.Combine(RootPath, $"packs/Microsoft.NETCore.App.{runtimeName}.{rid}/{RuntimeVersionName}/runtimes/{rid}/native"); + exists = Directory.Exists(path); + } if (exists) _hostRuntimes[new KeyValuePair(platform, arch)] = path; return exists; diff --git a/Source/Tools/Flax.Build/Build/Sdk.cs b/Source/Tools/Flax.Build/Build/Sdk.cs index 3a5239a3b..748751498 100644 --- a/Source/Tools/Flax.Build/Build/Sdk.cs +++ b/Source/Tools/Flax.Build/Build/Sdk.cs @@ -8,6 +8,19 @@ using Flax.Build.Platforms; namespace Flax.Build { + partial class Configuration + { + /// + /// Prints all SDKs found on system. Can be used to query Win10 SDK or any other platform-specific toolsets used by build tool. + /// + [CommandLine("printSDKs", "Prints all SDKs found on system. Can be used to query Win10 SDK or any other platform-specific toolsets used by build tool.")] + public static void PrintSDKs() + { + Log.Info("Printing SDKs..."); + Sdk.Print(); + } + } + /// /// The base class for all SDKs. /// @@ -45,17 +58,17 @@ namespace Flax.Build { var sdk = e.Value; if (sdk.IsValid) - Log.Info(sdk.GetType().Name + ", " + sdk.Version + ", " + sdk.RootPath); + Log.Message(sdk.GetType().Name + ", " + sdk.Version + ", " + sdk.RootPath); else - Log.Info(sdk.GetType().Name + ", missing"); + Log.Message(sdk.GetType().Name + ", missing"); } foreach (var e in WindowsPlatformBase.GetSDKs()) { - Log.Info("Windows SDK " + e.Key + ", " + WindowsPlatformBase.GetSDKVersion(e.Key) + ", " + e.Value); + Log.Message("Windows SDK " + e.Key + ", " + WindowsPlatformBase.GetSDKVersion(e.Key) + ", " + e.Value); } foreach (var e in WindowsPlatformBase.GetToolsets()) { - Log.Info("Windows Toolset " + e.Key + ", " + e.Value); + Log.Message("Windows Toolset " + e.Key + ", " + e.Value); } } diff --git a/Source/Tools/Flax.Build/CommandLine.cs b/Source/Tools/Flax.Build/CommandLine.cs index 91b741d59..91b6febce 100644 --- a/Source/Tools/Flax.Build/CommandLine.cs +++ b/Source/Tools/Flax.Build/CommandLine.cs @@ -14,6 +14,8 @@ namespace Flax.Build /// public class CommandLine { + internal static List ConsoleCommands; + /// /// The command line option data. /// @@ -426,6 +428,14 @@ namespace Flax.Build { type = property.PropertyType; } + else if (member is MethodInfo method) + { + // Add console command to be invoked by build tool + if (ConsoleCommands == null) + ConsoleCommands = new List(); + ConsoleCommands.Add(method); + continue; + } else { throw new Exception("Unknown member type."); diff --git a/Source/Tools/Flax.Build/CommandLineAttribute.cs b/Source/Tools/Flax.Build/CommandLineAttribute.cs index 84e0a9c29..90fb13b15 100644 --- a/Source/Tools/Flax.Build/CommandLineAttribute.cs +++ b/Source/Tools/Flax.Build/CommandLineAttribute.cs @@ -7,7 +7,7 @@ namespace Flax.Build /// /// The attribute to indicate the name of a command line argument and additional help description info. /// - [AttributeUsage(AttributeTargets.Field)] + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Method)] public class CommandLineAttribute : Attribute { /// diff --git a/Source/Tools/Flax.Build/Configuration.cs b/Source/Tools/Flax.Build/Configuration.cs index 1c88e037c..af7c05028 100644 --- a/Source/Tools/Flax.Build/Configuration.cs +++ b/Source/Tools/Flax.Build/Configuration.cs @@ -63,12 +63,6 @@ namespace Flax.Build [CommandLine("rebuild", "Rebuilds the targets.")] public static bool Rebuild = false; - /// - /// Prints all SDKs found on system. Can be used to query Win10 SDK or any other platform-specific toolsets used by build tool. - /// - [CommandLine("printSDKs", "Prints all SDKs found on system. Can be used to query Win10 SDK or any other platform-specific toolsets used by build tool.")] - public static bool PrintSDKs = false; - /// /// Prints all build system plugins. /// @@ -117,6 +111,12 @@ namespace Flax.Build [CommandLine("log", "Enables logging into console.")] public static bool ConsoleLog = false; + /// + /// Enables logging only messages into console (general info logs will be ignored)." + /// + [CommandLine("logMessagesOnly", "Enables logging only messages into console (general info logs will be ignored).")] + public static bool LogMessagesOnly = false; + /// /// Enables verbose logging and detailed diagnostics. /// @@ -138,9 +138,15 @@ namespace Flax.Build /// /// The log file path relative to the working directory. /// - [CommandLine("logfile", "", "The log file path relative to the working directory. Set to empty to disable it/")] + [CommandLine("logfile", "", "The log file path relative to the working directory. Set to empty to disable it.")] public static string LogFile = "Cache/Intermediate/Log.txt"; + /// + /// Enables logging only console output to the log file (instead whole output). + /// + [CommandLine("logFileWithConsole", "Enables logging only console output to the log file (instead whole output).")] + public static bool LogFileWithConsole = false; + /// /// The maximum allowed concurrency for a build system (maximum active worker threads count). /// diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs b/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs index c8598fd68..75e62a394 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/nethost.cs @@ -5,8 +5,11 @@ using System.Collections.Generic; using System.IO; using System.Xml; using Flax.Build; +using Flax.Build.Platforms; using Flax.Deploy; -using Ionic.Zip; +using System.IO.Compression; + +#pragma warning disable 0219 namespace Flax.Deps.Dependencies { @@ -28,6 +31,11 @@ namespace Flax.Deps.Dependencies { TargetPlatform.PS4, }; + case TargetPlatform.Linux: + return new[] + { + TargetPlatform.Android, + }; default: return new TargetPlatform[0]; } } @@ -143,6 +151,20 @@ namespace Flax.Deps.Dependencies } default: throw new InvalidPlatformException(BuildPlatform); } + if (AndroidNdk.Instance.IsValid) + { + var path = AndroidNdk.Instance.RootPath; + envVars.Add("ANDROID_NDK", path); + envVars.Add("ANDROID_NDK_HOME", path); + envVars.Add("ANDROID_NDK_ROOT", path); + } + if (AndroidSdk.Instance.IsValid) + { + var path = AndroidSdk.Instance.RootPath; + envVars.Add("ANDROID_SDK", path); + envVars.Add("ANDROID_SDK_HOME", path); + envVars.Add("ANDROID_SDK_ROOT", path); + } // Print the runtime version string version; @@ -155,9 +177,10 @@ namespace Flax.Deps.Dependencies // Build buildArgsBase = $"-os {os} -a {arch} -f {framework} -c {configuration} -lc {configuration} -rc {configuration} -rf {runtimeFlavor}{buildArgsBase}"; - foreach (var buildStep in new[] { subset, "host.pkg", "packs.product" }) + //foreach (var buildStep in new[] { subset, "host.pkg", "packs.product" }) + /*var buildStep = "host.pkg"; { - var buildArgs = $"{buildArgsBase} {buildStep}"; + var buildArgs = $"{buildArgsBase} -s {buildStep}"; if (BuildPlatform == TargetPlatform.Windows) { // For some reason running from Visual Studio fails the build so use command shell @@ -169,9 +192,10 @@ namespace Flax.Deps.Dependencies } else { - Utilities.Run(Path.Combine(root, buildScript), buildArgs, null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars); + //Utilities.Run(Path.Combine(root, buildScript), buildArgs, null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars); } - } + }*/ + Utilities.Run(Path.Combine(root, buildScript), buildArgsBase, null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars); // Deploy build products var dstBinaries = GetThirdPartyFolder(options, targetPlatform, architecture); @@ -194,18 +218,26 @@ namespace Flax.Deps.Dependencies var srcDotnetLibsPkg = Path.Combine(artifacts, "packages", "Release", "Shipping", $"Microsoft.NETCore.App.Runtime.Mono.{hostRuntimeName}.{version}.nupkg"); if (!File.Exists(srcDotnetLibsPkg)) throw new Exception($"Missing .NET Core App class library package at '{srcDotnetLibsPkg}'"); - var srcDotnetLibsPkgTemp = srcDotnetLibsPkg + "Temp"; - using (var zip = new ZipFile(srcDotnetLibsPkg)) + var unpackTemp = Path.Combine(Path.GetDirectoryName(srcDotnetLibsPkg), "UnpackTemp"); + SetupDirectory(unpackTemp, true); + using (var zip = ZipFile.Open(srcDotnetLibsPkg, ZipArchiveMode.Read)) { - zip.ExtractAll(srcDotnetLibsPkgTemp, ExtractExistingFileAction.OverwriteSilently); + zip.ExtractToDirectory(unpackTemp); } var privateCorelib = "System.Private.CoreLib.dll"; - Utilities.FileCopy(Path.Combine(srcDotnetLibsPkgTemp, "runtimes", hostRuntimeName, "native", privateCorelib), Path.Combine(dstClassLibrary, privateCorelib)); - Utilities.DirectoryCopy(Path.Combine(srcDotnetLibsPkgTemp, "runtimes", hostRuntimeName, "lib", "net7.0"), dstClassLibrary, false, true); - Utilities.DirectoriesDelete(srcDotnetLibsPkgTemp); + Utilities.FileCopy(Path.Combine(unpackTemp, "runtimes", hostRuntimeName, "native", privateCorelib), Path.Combine(dstClassLibrary, privateCorelib)); + Utilities.DirectoryCopy(Path.Combine(unpackTemp, "runtimes", hostRuntimeName, "lib", "net7.0"), dstClassLibrary, false, true); // TODO: host/fxr//hostfxr.dll // TODO: shared/Microsoft.NETCore.App//hostpolicy.dl // TODO: shared/Microsoft.NETCore.App//System.IO.Compression.Native.dll + if (runtimeFlavor == "Mono") + { + Utilities.DirectoryCopy(Path.Combine(unpackTemp, "runtimes", hostRuntimeName, "native"), Path.Combine(dstDotnet, "native"), true, true); + Utilities.FileDelete(Path.Combine(dstDotnet, "native", privateCorelib)); + } + else + throw new InvalidPlatformException(targetPlatform); + Utilities.DirectoriesDelete(unpackTemp); } /// @@ -233,6 +265,11 @@ namespace Flax.Deps.Dependencies Build(options, platform, TargetArchitecture.x64); break; } + case TargetPlatform.Android: + { + Build(options, platform, TargetArchitecture.ARM64); + break; + } } } diff --git a/Source/Tools/Flax.Build/Deps/Dependency.cs b/Source/Tools/Flax.Build/Deps/Dependency.cs index b0bec87ea..89573737c 100644 --- a/Source/Tools/Flax.Build/Deps/Dependency.cs +++ b/Source/Tools/Flax.Build/Deps/Dependency.cs @@ -132,6 +132,8 @@ namespace Flax.Deps cmdLine += " --recurse-submodules"; Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.None); + if (submodules) + Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.None); } if (commit != null) @@ -158,6 +160,8 @@ namespace Flax.Deps cmdLine += " --recurse-submodules"; Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.None); + if (submodules) + Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.None); } } @@ -183,6 +187,8 @@ namespace Flax.Deps cmdLine += " --recurse-submodules"; Utilities.Run("git", cmdLine, null, null, Utilities.RunOptions.None); + if (submodules) + Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.None); } if (commit != null) @@ -208,6 +214,8 @@ namespace Flax.Deps cmdLine += " --recurse-submodules"; Utilities.Run("git", cmdLine, null, path, Utilities.RunOptions.None); + if (submodules) + Utilities.Run("git", "submodule update --init --recursive", null, null, Utilities.RunOptions.None); if (commit != null) { diff --git a/Source/Tools/Flax.Build/Log.cs b/Source/Tools/Flax.Build/Log.cs index b8fc62ddd..7a7869cb5 100644 --- a/Source/Tools/Flax.Build/Log.cs +++ b/Source/Tools/Flax.Build/Log.cs @@ -74,6 +74,8 @@ namespace Flax.Build System.Diagnostics.Debug.WriteLine(Indent + message); } } + else if (Configuration.LogFileWithConsole) + return; if (_logFile != null) { @@ -82,7 +84,10 @@ namespace Flax.Build lock (_logFile) { - _logFileWriter.WriteLine(prefix + Indent + message); + if (Configuration.LogFileWithConsole) + _logFileWriter.WriteLine(message); + else + _logFileWriter.WriteLine(prefix + Indent + message); } } } @@ -101,6 +106,15 @@ namespace Flax.Build /// /// The message. public static void Info(string message) + { + Write(message, _defaultColor, Configuration.ConsoleLog && !Configuration.LogMessagesOnly); + } + + /// + /// Logs the information. + /// + /// The message. + public static void Message(string message) { Write(message, _defaultColor, Configuration.ConsoleLog); } diff --git a/Source/Tools/Flax.Build/Program.cs b/Source/Tools/Flax.Build/Program.cs index a1a03d7b9..089ab9ed6 100644 --- a/Source/Tools/Flax.Build/Program.cs +++ b/Source/Tools/Flax.Build/Program.cs @@ -73,7 +73,7 @@ namespace Flax.Build Globals.Project = ProjectInfo.Load(projectFiles[0]); else if (projectFiles.Length > 1) throw new Exception("Too many project files. Don't know which to pick."); - else + else if (!Configuration.LogMessagesOnly) Log.Warning("Missing project file."); } @@ -114,11 +114,11 @@ namespace Flax.Build // Collect all targets and modules from the workspace Builder.GenerateRulesAssembly(); - // Print SDKs - if (Configuration.PrintSDKs) + // Run console commands + if (CommandLine.ConsoleCommands != null) { - Log.Info("Printing SDKs..."); - Sdk.Print(); + foreach (var e in CommandLine.ConsoleCommands) + e.Invoke(null, null); } // Deps tool