diff --git a/Source/ThirdParty/nethost/nethost.Build.cs b/Source/ThirdParty/nethost/nethost.Build.cs index 8b355d765..75a8a3ab6 100644 --- a/Source/ThirdParty/nethost/nethost.Build.cs +++ b/Source/ThirdParty/nethost/nethost.Build.cs @@ -32,7 +32,7 @@ public class nethost : ThirdPartyModule // Get .NET SDK runtime host var dotnetSdk = DotNetSdk.Instance; if (!dotnetSdk.IsValid) - throw new Exception($"Missing NET SDK {DotNetSdk.MinimumVersion}."); + throw new DotNetSdk.MissingException(); if (!dotnetSdk.GetHostRuntime(options.Platform.Target, options.Architecture, out var hostRuntime)) { if (options.Target.IsPreBuilt) diff --git a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs index 6e9fbea83..c8e709d86 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs @@ -164,7 +164,7 @@ namespace Flax.Build #if USE_NETCORE var dotnetSdk = DotNetSdk.Instance; if (!dotnetSdk.IsValid) - throw new Exception("Cannot compile C# without .NET SDK"); + throw new DotNetSdk.MissingException(); string dotnetPath = "dotnet", referenceAnalyzers; string[] runtimeVersionNameParts = dotnetSdk.RuntimeVersionName.Split('.'); string runtimeVersionShort = runtimeVersionNameParts[0] + '.' + runtimeVersionNameParts[1]; diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs index 8eea4d6dd..e7506d363 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs @@ -106,6 +106,20 @@ namespace Flax.Build } } + /// + /// Exception when .NET SDK is missing. + /// + public sealed class MissingException : Exception + { + /// + /// Init with a proper message. + /// + public MissingException() + : base(string.IsNullOrEmpty(Configuration.Dotnet) ? $"Missing .NET SDK {MinimumVersion} (or higher)." : $"Missing .NET SDK {Configuration.Dotnet}.") + { + } + } + private Dictionary, HostRuntime> _hostRuntimes = new(); /// @@ -223,7 +237,7 @@ namespace Flax.Build // We need to support two paths here: // 1. We are running an x64 binary and we are running on an arm64 host machine // 2. We are running an Arm64 binary and we are targeting an x64 host machine - if (Flax.Build.Platforms.MacPlatform.GetProcessIsTranslated() || isRunningOnArm64Targetx64) + if (Flax.Build.Platforms.MacPlatform.GetProcessIsTranslated() || isRunningOnArm64Targetx64) { rid = "osx-x64"; dotnetPath = Path.Combine(dotnetPath, "x64"); @@ -260,18 +274,23 @@ namespace Flax.Build Log.Verbose($"Found the following .NET SDK versions: {string.Join(", ", dotnetSdkVersions)}"); Log.Verbose($"Found the following .NET runtime versions: {string.Join(", ", dotnetRuntimeVersions)}"); - string dotnetSdkVersion = dotnetSdkVersions.FirstOrDefault(x => ParseVersion(x).Major >= MinimumVersion.Major && ParseVersion(x).Major <= MaximumVersion.Major); - string dotnetRuntimeVersion = dotnetRuntimeVersions.FirstOrDefault(x => ParseVersion(x).Major >= MinimumVersion.Major && ParseVersion(x).Major <= MaximumVersion.Major); + var dotnetSdkVersion = GetVersion(dotnetSdkVersions); + var dotnetRuntimeVersion = GetVersion(dotnetRuntimeVersions); + var minVer = string.IsNullOrEmpty(Configuration.Dotnet) ? MinimumVersion.ToString() : Configuration.Dotnet; if (string.IsNullOrEmpty(dotnetSdkVersion)) - dotnetSdkVersion = dotnetPath; - if (dotnetSdkVersion == null && dotnetSdkVersions.Count() > 0) { - Log.Warning($"Unsupported .NET SDK {dotnetSdkVersions.First()} version found. Minimum version required is .NET {MinimumVersion}."); + if (dotnetSdkVersions.Any()) + Log.Warning($"Unsupported .NET SDK versions found: {string.Join(", ", dotnetSdkVersions)}. Minimum version required is .NET {minVer}."); + else + Log.Warning($"Missing .NET SDK. Minimum version required is .NET {minVer}."); return; } - if (string.IsNullOrEmpty(dotnetSdkVersion) || string.IsNullOrEmpty(dotnetRuntimeVersion)) + if (string.IsNullOrEmpty(dotnetRuntimeVersion)) { - Log.Warning("Missing .NET SDK"); + if (dotnetRuntimeVersions.Any()) + Log.Warning($"Unsupported .NET runtime versions found: {string.Join(", ", dotnetRuntimeVersions)}. Minimum version required is .NET {minVer}."); + else + Log.Warning($"Missing .NET runtime. Minimum version required is .NET {minVer}."); return; } RootPath = dotnetPath; @@ -434,7 +453,7 @@ namespace Flax.Build exists = Directory.Exists(path); if (exists) - _hostRuntimes[new KeyValuePair(platform, arch)] = new HostRuntime(platform, path); + _hostRuntimes[new KeyValuePair(platform, arch)] = new HostRuntime(platform, Utilities.NormalizePath(path)); return exists; } @@ -456,6 +475,8 @@ namespace Flax.Build } if (!Version.TryParse(version, out var ver)) return null; + if (ver.Build == -1) + return new Version(ver.Major, ver.Minor); return new Version(ver.Major, ver.Minor, ver.Build, rev); } @@ -466,9 +487,42 @@ namespace Flax.Build private static string GetVersion(IEnumerable versions) { - return versions.OrderByDescending(ParseVersion) - .Where(x => ParseVersion(x).Major >= MinimumVersion.Major && ParseVersion(x).Major <= MaximumVersion.Major) - .FirstOrDefault(); + Version dotnetVer = null; + int dotnetVerNum = -1; + if (!string.IsNullOrEmpty(Configuration.Dotnet)) + { + dotnetVer = ParseVersion(Configuration.Dotnet); + if (int.TryParse(Configuration.Dotnet, out var tmp) && tmp >= MinimumVersion.Major) + dotnetVerNum = tmp; + } + var sorted = versions.OrderByDescending(ParseVersion); + foreach (var version in sorted) + { + var v = ParseVersion(version); + + // Filter by version specified in command line + if (dotnetVer != null) + { + if (dotnetVer.Major != v.Major) + continue; + if (dotnetVer.Minor != v.Minor) + continue; + if (dotnetVer.Revision != -1 && dotnetVer.Revision != v.Revision) + continue; + if (dotnetVer.Build != -1 && dotnetVer.Build != v.Build) + continue; + } + else if (dotnetVerNum != -1) + { + if (dotnetVerNum != v.Major) + continue; + } + + // Filter by min/max versions supported by Flax.Build + if (v.Major >= MinimumVersion.Major && v.Major <= MaximumVersion.Major) + return version; + } + return null; } private static bool IsValidVersion(string versionPath) diff --git a/Source/Tools/Flax.Build/Configuration.cs b/Source/Tools/Flax.Build/Configuration.cs index 8ca11b007..f58ffcaf3 100644 --- a/Source/Tools/Flax.Build/Configuration.cs +++ b/Source/Tools/Flax.Build/Configuration.cs @@ -225,10 +225,24 @@ namespace Flax.Build [CommandLine("compiler", "", "Overrides the compiler to use for building. Eg. v140 overrides the toolset when building for Windows.")] public static string Compiler = null; + /// + /// Specifies the dotnet SDK version to use for the build. Eg. set to '7' to use .NET 7 even if .NET 8 is installed. + /// + [CommandLine("dotnet", "", "Specifies the dotnet SDK version to use for the build. Eg. set to '7' to use .NET 7 even if .NET 8 is installed.")] + public static string Dotnet = null; + /// /// Custom configuration defines provided via command line for the build tool. /// public static List CustomDefines = new List(); + + internal static void PassArgs(ref string cmdLine) + { + if (!string.IsNullOrEmpty(Compiler)) + cmdLine += " -compiler=" + Compiler; + if (!string.IsNullOrEmpty(Dotnet)) + cmdLine += " -dotnet=" + Dotnet; + } } /// diff --git a/Source/Tools/Flax.Build/Deploy/FlaxBuild.cs b/Source/Tools/Flax.Build/Deploy/FlaxBuild.cs index b4e8b8680..13f467ccf 100644 --- a/Source/Tools/Flax.Build/Deploy/FlaxBuild.cs +++ b/Source/Tools/Flax.Build/Deploy/FlaxBuild.cs @@ -17,8 +17,7 @@ namespace Flax.Deploy var flaxBuildTool = Path.Combine(Globals.EngineRoot, buildPlatform == TargetPlatform.Windows ? "Binaries/Tools/Flax.Build.exe" : "Binaries/Tools/Flax.Build"); var format = "-build -buildtargets={0} -log -logfile= -perf -platform={1} -arch={2} -configuration={3}"; var cmdLine = string.Format(format, target, platform, architecture, configuration); - if (!string.IsNullOrEmpty(Configuration.Compiler)) - cmdLine += " -compiler=" + Configuration.Compiler; + Configuration.PassArgs(ref cmdLine); Log.Info($"Building {target} for {platform} {architecture} {configuration}..."); int result = Utilities.Run(flaxBuildTool, cmdLine, null, root); diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs index 84607f6a1..4eba06cb0 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs @@ -172,8 +172,7 @@ namespace Flax.Build.Projects.VisualStudio configuration.Configuration, configuration.Platform, target.Name); - if (!string.IsNullOrEmpty(Configuration.Compiler)) - cmdLine += " -compiler=" + Configuration.Compiler; + Configuration.PassArgs(ref cmdLine); vcProjectFileContent.AppendLine(string.Format(" ", configuration.Name)); if (platform is IVisualStudioProjectCustomizer customizer) diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs index eda2f7a95..b04531d9f 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs @@ -731,8 +731,7 @@ namespace Flax.Build.Projects.VisualStudio configuration.Configuration, configuration.Platform, configuration.Target); - if (!string.IsNullOrEmpty(Configuration.Compiler)) - cmdLine += " -compiler=" + Configuration.Compiler; + Configuration.PassArgs(ref cmdLine); str.AppendLine(string.Format(" ", cmdLine, extraArgs, configuration.Name)); } diff --git a/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs index 5c4b2dbe0..15b236972 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs @@ -201,6 +201,8 @@ namespace Flax.Build.Projects.VisualStudioCode json.AddUnnamedField(string.Format("-buildTargets={0}", target.Name)); if (!string.IsNullOrEmpty(Configuration.Compiler)) json.AddUnnamedField(string.Format("-compiler={0}", Configuration.Compiler)); + if (!string.IsNullOrEmpty(Configuration.Dotnet)) + json.AddUnnamedField(string.Format("-dotnet={0}", Configuration.Dotnet)); } json.EndArray(); @@ -228,6 +230,8 @@ namespace Flax.Build.Projects.VisualStudioCode json.AddUnnamedField(string.Format("--buildTargets={0}", target.Name)); if (!string.IsNullOrEmpty(Configuration.Compiler)) json.AddUnnamedField(string.Format("--compiler={0}", Configuration.Compiler)); + if (!string.IsNullOrEmpty(Configuration.Dotnet)) + json.AddUnnamedField(string.Format("-dotnet={0}", Configuration.Dotnet)); } json.EndArray(); @@ -255,6 +259,8 @@ namespace Flax.Build.Projects.VisualStudioCode json.AddUnnamedField(string.Format("--buildTargets={0}", target.Name)); if (!string.IsNullOrEmpty(Configuration.Compiler)) json.AddUnnamedField(string.Format("--compiler={0}", Configuration.Compiler)); + if (!string.IsNullOrEmpty(Configuration.Dotnet)) + json.AddUnnamedField(string.Format("-dotnet={0}", Configuration.Dotnet)); } json.EndArray();