diff --git a/Flax.flaxproj b/Flax.flaxproj index bd64ab7e8..52c466fd7 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -11,6 +11,7 @@ "EditorTarget": "FlaxEditor", "Configuration": { "UseCSharp": true, - "UseLargeWorlds": false + "UseLargeWorlds": false, + "UseDotNet": true } } \ No newline at end of file diff --git a/Source/Engine/Scripting/Scripting.Build.cs b/Source/Engine/Scripting/Scripting.Build.cs index b18a9b1ef..2acb906d7 100644 --- a/Source/Engine/Scripting/Scripting.Build.cs +++ b/Source/Engine/Scripting/Scripting.Build.cs @@ -15,7 +15,10 @@ public class Scripting : EngineModule if (EngineConfiguration.WithCSharp(options)) { - options.PublicDependencies.Add("mono"); + if (EngineConfiguration.UseDotNet) + options.PublicDependencies.Add("nethost"); + else + options.PublicDependencies.Add("mono"); } options.PrivateDependencies.Add("Utilities"); diff --git a/Source/ThirdParty/nethost/FlaxEngine.CSharp.runtimeconfig.json b/Source/ThirdParty/nethost/FlaxEngine.CSharp.runtimeconfig.json new file mode 100644 index 000000000..9c7f14dd0 --- /dev/null +++ b/Source/ThirdParty/nethost/FlaxEngine.CSharp.runtimeconfig.json @@ -0,0 +1,9 @@ +{ + "runtimeOptions": { + "tfm": "net7.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "7.0.0-rc.2.22472.3" + } + } +} \ No newline at end of file diff --git a/Source/ThirdParty/nethost/LICENSE.TXT b/Source/ThirdParty/nethost/LICENSE.TXT new file mode 100644 index 000000000..a616ed188 --- /dev/null +++ b/Source/ThirdParty/nethost/LICENSE.TXT @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Source/ThirdParty/nethost/nethost.Build.cs b/Source/ThirdParty/nethost/nethost.Build.cs new file mode 100644 index 000000000..d101ff0a5 --- /dev/null +++ b/Source/ThirdParty/nethost/nethost.Build.cs @@ -0,0 +1,92 @@ +// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. + +using System.Collections.Generic; +using System.IO; +using System; +using Flax.Build; +using Flax.Build.NativeCpp; +using Flax.Build.Platforms; +using Microsoft.Win32; +using System.Linq; + +/// +/// Module for nethost (.NET runtime host library) +/// +public class nethost : ThirdPartyModule +{ + /// + public override void Init() + { + base.Init(); + + LicenseType = LicenseTypes.MIT; + LicenseFilePath = "LICENSE.TXT"; + + // Merge third-party modules into engine binary + BinaryModuleName = "FlaxEngine"; + } + + /// + private static Version ParseVersion(string version) + { + // Give precedence to final releases over release candidate / beta releases + int rev = 9999; + if (version.Contains("-")) // e.g. 7.0.0-rc.2.22472.3 + { + version = version.Substring(0, version.IndexOf("-")); + rev = 0; + } + Version ver = new Version(version); + return new Version(ver.Major, ver.Minor, ver.Build, rev); + } + + /// + public override void Setup(BuildOptions options) + { + base.Setup(options); + + options.SourceFiles.Clear(); + + string appHostRuntimePath; + if (options.Platform.Target == TargetPlatform.Windows) + { + // NOTE: nethost is bundled with SDK, not runtime. Should C# scripting have a hard requirement for SDK to be installed? + + string arch = "x64"; //options.Architecture == TargetArchitecture.x64 ? "x64" : "x86"; + + using RegistryKey baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); + + using RegistryKey hostKey = baseKey.OpenSubKey(@$"SOFTWARE\dotnet\Setup\InstalledVersions\{arch}\sharedhost"); + string dotnetPath = (string)hostKey.GetValue("Path"); + + using RegistryKey runtimeKey = baseKey.OpenSubKey(@$"SOFTWARE\WOW6432Node\dotnet\Setup\InstalledVersions\{arch}\sharedfx\Microsoft.NETCore.App"); + string[] versions = runtimeKey.GetValueNames(); + + string dotnetVersion = versions.OrderByDescending(x => ParseVersion(x)).FirstOrDefault(); + + if (string.IsNullOrEmpty(dotnetPath)) + dotnetPath = Environment.GetEnvironmentVariable("DOTNET_ROOT"); + + if (string.IsNullOrEmpty(dotnetPath) || string.IsNullOrEmpty(dotnetVersion)) + throw new Exception("Failed to find dotnet installation"); + + int majorVersion = int.Parse(dotnetVersion.Substring(0, dotnetVersion.IndexOf("."))); + if (majorVersion < 7) + throw new Exception($"Unsupported dotnet version found, minimum version required is .NET 7 (found {dotnetVersion})"); + + appHostRuntimePath = String.Format("{0}packs\\Microsoft.NETCore.App.Host.win-{1}\\{2}\\runtimes\\win-{1}\\native", dotnetPath, arch, dotnetVersion); + options.OutputFiles.Add(Path.Combine(appHostRuntimePath, "nethost.lib")); + options.DependencyFiles.Add(Path.Combine(appHostRuntimePath, "nethost.dll")); + options.PublicIncludePaths.Add(appHostRuntimePath); + } + else + { + // /etc/dotnet/install_location + throw new InvalidPlatformException(options.Platform.Target); + } + + options.PublicIncludePaths.Add(appHostRuntimePath); + options.ScriptingAPI.Defines.Add("USE_NETCORE"); + options.DependencyFiles.Add(Path.Combine(FolderPath, "FlaxEngine.CSharp.runtimeconfig.json")); + } +} diff --git a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs index 3303a95ea..abcb52a28 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs @@ -5,7 +5,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; using Flax.Build.Graph; +using Flax.Build.Platforms; using Flax.Deploy; +using Microsoft.Win32; using Task = Flax.Build.Graph.Task; namespace Flax.Build @@ -152,7 +154,7 @@ namespace Flax.Build var outputPath = Path.GetDirectoryName(buildData.Target.GetOutputFilePath(buildOptions)); var outputFile = Path.Combine(outputPath, name + ".dll"); var outputDocFile = Path.Combine(outputPath, name + ".xml"); - string monoRoot, monoPath, cscPath; + string monoRoot, monoPath, cscPath, referenceAssemblies, referenceAnalyzers; switch (buildPlatform) { case TargetPlatform.Windows: @@ -163,11 +165,43 @@ namespace Flax.Build monoPath = null; cscPath = Path.Combine(Path.GetDirectoryName(VCEnvironment.MSBuildPath), "Roslyn", "csc.exe"); - if (!File.Exists(cscPath)) + // dotnet + if (WindowsPlatformBase.TryReadDirRegistryKey(@"HKEY_LOCAL_MACHINE\SOFTWARE\dotnet\Setup\InstalledVersions\x64\sharedhost", "Path", out string dotnetPath)) + { + static Version ParseVersion(string version) + { + // Give precedence to final releases over release candidate / beta releases + int rev = 9999; + if (version.Contains("-")) // e.g. 7.0.0-rc.2.22472.3 + { + version = version.Substring(0, version.IndexOf("-")); + rev = 0; + } + Version ver = new Version(version); + return new Version(ver.Major, ver.Minor, ver.Build, rev); + } +#pragma warning disable CA1416 + string arch = "x64"; + using RegistryKey baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); + using RegistryKey sdkVersionsKey = baseKey.OpenSubKey($@"SOFTWARE\WOW6432Node\dotnet\Setup\InstalledVersions\{arch}\sdk"); + using RegistryKey sharedfxVersionsKey = baseKey.OpenSubKey($@"SOFTWARE\WOW6432Node\dotnet\Setup\InstalledVersions\{arch}\sharedfx\Microsoft.NETCore.App"); + using RegistryKey hostfxrKey = baseKey.OpenSubKey($@"SOFTWARE\WOW6432Node\dotnet\Setup\InstalledVersions\{arch}\hostfxr"); + + string dotnetSdkVersion = sdkVersionsKey.GetValueNames().OrderByDescending(x => ParseVersion(x)).FirstOrDefault(); + string dotnetSharedfxVersion = sharedfxVersionsKey.GetValueNames().OrderByDescending(x => ParseVersion(x)).FirstOrDefault(); + string dotnetHostfxrVersion = (string)hostfxrKey.GetValue("Version"); +#pragma warning restore CA1416 + cscPath = @$"{dotnetPath}sdk\{dotnetSdkVersion}\Roslyn\bincore\csc.dll"; + referenceAssemblies = @$"{dotnetPath}shared\Microsoft.NETCore.App\{dotnetSharedfxVersion}\"; + referenceAnalyzers = @$"{dotnetPath}packs\Microsoft.NETCore.App.Ref\{dotnetSharedfxVersion}\analyzers\dotnet\cs\"; + } + else //if (!File.Exists(cscPath)) { // Fallback to Mono binaries monoPath = Path.Combine(monoRoot, "bin", "mono.exe"); cscPath = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe"); + referenceAssemblies = Path.Combine(monoRoot, "lib", "mono", "4.5-api"); + referenceAnalyzers = ""; } break; } @@ -175,15 +209,19 @@ namespace Flax.Build monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Linux", "Mono"); monoPath = Path.Combine(monoRoot, "bin", "mono"); cscPath = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe"); + referenceAssemblies = Path.Combine(monoRoot, "lib", "mono", "4.5-api"); + referenceAnalyzers = ""; break; case TargetPlatform.Mac: monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Mac", "Mono"); monoPath = Path.Combine(monoRoot, "bin", "mono"); cscPath = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe"); + referenceAssemblies = Path.Combine(monoRoot, "lib", "mono", "4.5-api"); + referenceAnalyzers = ""; break; default: throw new InvalidPlatformException(buildPlatform); } - var referenceAssemblies = Path.Combine(monoRoot, "lib", "mono", "4.5-api"); + if (fileReferences == null) fileReferences = buildOptions.ScriptingAPI.FileReferences; else @@ -207,9 +245,11 @@ namespace Flax.Build args.Add("/warn:4"); args.Add("/unsafe"); args.Add("/fullpaths"); - args.Add("/langversion:7.3"); + args.Add("/filealign:512"); + args.Add("/langversion:latest"); if (buildOptions.ScriptingAPI.IgnoreMissingDocumentationWarnings) args.Add("-nowarn:1591"); + args.Add("-nowarn:8632"); // nullable args.Add(buildData.Configuration == TargetConfiguration.Debug ? "/optimize-" : "/optimize+"); args.Add(string.Format("/out:\"{0}\"", outputFile)); args.Add(string.Format("/doc:\"{0}\"", outputDocFile)); @@ -217,11 +257,13 @@ namespace Flax.Build args.Add("/define:" + string.Join(";", buildOptions.ScriptingAPI.Defines)); if (buildData.Configuration == TargetConfiguration.Debug) args.Add("/define:DEBUG"); - args.Add(string.Format("/reference:\"{0}{1}mscorlib.dll\"", referenceAssemblies, Path.DirectorySeparatorChar)); + args.Add(string.Format("/reference:\"{0}mscorlib.dll\"", referenceAssemblies)); foreach (var reference in buildOptions.ScriptingAPI.SystemReferences) - args.Add(string.Format("/reference:\"{0}{2}{1}.dll\"", referenceAssemblies, reference, Path.DirectorySeparatorChar)); + args.Add(string.Format("/reference:\"{0}{1}.dll\"", referenceAssemblies, reference)); foreach (var reference in fileReferences) args.Add(string.Format("/reference:\"{0}\"", reference)); + foreach (var analyzer in buildOptions.ScriptingAPI.SystemAnalyzers) + args.Add(string.Format("/analyzer:\"{0}{1}.dll\"", referenceAnalyzers, analyzer)); foreach (var sourceFile in sourceFiles) args.Add("\"" + sourceFile + "\""); @@ -249,8 +291,8 @@ namespace Flax.Build // The "/shared" flag enables the compiler server support: // https://github.com/dotnet/roslyn/blob/main/docs/compilers/Compiler%20Server.md - task.CommandPath = cscPath; - task.CommandArguments = $"/noconfig /shared @\"{responseFile}\""; + task.CommandPath = "dotnet.exe"; + task.CommandArguments = $"exec \"{cscPath}\" /noconfig /shared @\"{responseFile}\""; } BuildDotNetAssembly?.Invoke(graph, buildData, buildOptions, task, binaryModule); diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs index 6cad222ba..c759719c3 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs @@ -156,6 +156,11 @@ namespace Flax.Build.NativeCpp /// public HashSet FileReferences; + /// + /// The .Net libraries references (dll or exe files paths). + /// + public HashSet SystemAnalyzers; + /// /// True if ignore compilation warnings due to missing code documentation comments. /// @@ -182,9 +187,53 @@ namespace Flax.Build.NativeCpp Defines = new HashSet(), SystemReferences = new HashSet { + "Microsoft.CSharp", "System", - "System.Xml", + + "System.Collections", + "System.Collections.Concurrent", + "System.Collections.NonGeneric", + "System.Collections.Specialized", + "System.Collections.Immutable", + "System.ComponentModel", + "System.ComponentModel.DataAnnotations", + "System.ComponentModel.Primitives", + "System.ComponentModel.TypeConverter", + "System.Console", "System.Core", + "System.Globalization", + "System.IO", + "System.IO.Compression", + "System.IO.FileSystem.Watcher", + "System.Linq", + "System.Linq.Expressions", + "System.Net.Http", + "System.Net.Primitives", + "System.ObjectModel", + "System.Private.CoreLib", + "System.Private.Uri", + "System.Private.Xml", + + "System.Reflection", + "System.Runtime", + "System.Runtime.CompilerServices.Unsafe", + "System.Runtime.InteropServices", + "System.Runtime.InteropServices.RuntimeInformation", + "System.Runtime.Serialization.Formatters", // BinaryFormatter + "System.Security.Cryptography", + "System.Security.Cryptography.Algorithms", + "System.Security.Cryptography.Primitives", + "System.Text.RegularExpressions", + "System.Threading.Tasks.Parallel", + "System.Xml", + + "System.Reflection.Metadata", + "netstandard", + }, + SystemAnalyzers = new HashSet + { + @"Microsoft.Interop.LibraryImportGenerator", + @"Microsoft.Interop.SourceGeneration", }, FileReferences = new HashSet(), }; diff --git a/Source/Tools/Flax.Build/Configuration.cs b/Source/Tools/Flax.Build/Configuration.cs index 4c3f63b0c..33b40cf05 100644 --- a/Source/Tools/Flax.Build/Configuration.cs +++ b/Source/Tools/Flax.Build/Configuration.cs @@ -242,6 +242,12 @@ namespace Flax.Build [CommandLine("useCSharp", "0 to disable C# support in build")] public static bool UseCSharp = true; + /// + /// True if .NET support should be enabled. + /// + [CommandLine("useDotNet", "1 to enable .NET support in build, 0 to enable Mono support in build")] + public static bool UseDotNet = true; + public static bool WithCSharp(NativeCpp.BuildOptions options) { if (options.Platform.Target == TargetPlatform.PS5) @@ -254,5 +260,10 @@ namespace Flax.Build // This can be used to selectively control 64-bit coordinates per-platform or build configuration return UseLargeWorlds; } + + public static bool WithDotNet(NativeCpp.BuildOptions options) + { + return UseDotNet; + } } } diff --git a/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs b/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs index 0ca955324..5a0d96b27 100644 --- a/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs +++ b/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs @@ -9,6 +9,8 @@ using Flax.Build.Platforms; using Flax.Build.Projects.VisualStudio; using Microsoft.Win32; +#pragma warning disable CA1416 + namespace Flax.Deploy { /// @@ -286,3 +288,5 @@ namespace Flax.Deploy } } } + +#pragma warning restore CA1416 diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs index 2673ec817..2416a614a 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs @@ -11,6 +11,8 @@ using Flax.Build.Projects.VisualStudio; using Flax.Build.Projects.VisualStudioCode; using Microsoft.Win32; +#pragma warning disable CA1416 + namespace Flax.Build.Platforms { /// @@ -523,3 +525,5 @@ namespace Flax.Build.Platforms } } } + +#pragma warning restore CA1416 diff --git a/Source/Tools/Flax.Build/Properties/AssemblyInfo.cs b/Source/Tools/Flax.Build/Properties/AssemblyInfo.cs deleted file mode 100644 index 48e41e772..000000000 --- a/Source/Tools/Flax.Build/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. - -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Flax.Build")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Wojciech Figat")] -[assembly: AssemblyProduct("Flax.Build")] -[assembly: AssemblyCopyright("Copyright © 2012-2022 Wojciech Figat")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] -[assembly: Guid("c99aaf92-d4ad-4847-9ee0-b11e68e93e1e")] -[assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("1.0.0.0")]