From 7f010d8ec2f77c456c9ecb470b46a12bc8c6b698 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Thu, 2 Jun 2022 19:03:06 +0100 Subject: [PATCH 1/3] Allow text templating to work in Visual Studio for Mac Running the text templating engine within Visual Studio for Mac fails since the RuntimeInfo fails to find any SDK directory. When using the Roslyn code compiler there is now no exception if no SDK is found. The SDK location is not needed for the Roslyn compiler since there is no external csc.dll to run. Also use a better default C# lang version for the Roslyn code compiler instead of 7.0 --- .../TemplatingEngineExtension.cs | 3 +++ .../RuntimeInfo.cs | 19 ++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Mono.TextTemplating.Roslyn/TemplatingEngineExtension.cs b/Mono.TextTemplating.Roslyn/TemplatingEngineExtension.cs index 20a6fa3..8ca6d8e 100644 --- a/Mono.TextTemplating.Roslyn/TemplatingEngineExtension.cs +++ b/Mono.TextTemplating.Roslyn/TemplatingEngineExtension.cs @@ -9,6 +9,9 @@ public static class RoslynTemplatingEngineExtensions public static void UseInProcessCompiler (this TemplatingEngine engine) { engine.SetCompilerFunc ((RuntimeInfo r) => new RoslynCodeCompiler (r)); + + RuntimeInfo.ThrowOnMissingDotNetCoreSdkDirectory = false; + RuntimeInfo.DefaultMaxSupportedLangVersion = CSharpLangVersion.v9_0; } public static void UseInProcessCompiler (this TemplateGenerator generator) diff --git a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs index 02bd5ab..fb6b082 100644 --- a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs +++ b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs @@ -56,6 +56,9 @@ class RuntimeInfo public string RefAssembliesDir { get; private set; } public string RuntimeFacadesDir { get; internal set; } + internal static bool ThrowOnMissingDotNetCoreSdkDirectory { get; set; } = true; + internal static CSharpLangVersion? DefaultMaxSupportedLangVersion { get; set; } + public static RuntimeInfo GetRuntime () { if (Type.GetType ("Mono.Runtime") != null) @@ -135,10 +138,16 @@ static RuntimeInfo GetDotNetCoreSdk () string MakeCscPath (string d) => Path.Combine (d, "Roslyn", "bincore", "csc.dll"); var sdkDir = FindHighestVersionedDirectory (Path.Combine (dotnetRoot, "sdk"), d => File.Exists (MakeCscPath (d)), out var sdkVersion); - if (sdkDir == null) { + if (sdkDir == null && ThrowOnMissingDotNetCoreSdkDirectory) { return FromError (RuntimeKind.NetCore, "Could not find csc.dll in any .NET Core SDK"); } - var maxCSharpVersion = CSharpLangVersionHelper.FromNetCoreSdkVersion (sdkVersion); + string cscPath = sdkDir == null ? null : MakeCscPath (sdkDir); + CSharpLangVersion maxCSharpVersion; + if (sdkVersion.Equals(SemVersion.Zero) && DefaultMaxSupportedLangVersion.HasValue) { + maxCSharpVersion = DefaultMaxSupportedLangVersion.Value; + } else { + maxCSharpVersion = CSharpLangVersionHelper.FromNetCoreSdkVersion (sdkVersion); + } // it's ok if this is null, we may be running on an older SDK that didn't support packs //in which case we fall back to resolving from the runtime dir @@ -148,11 +157,15 @@ static RuntimeInfo GetDotNetCoreSdk () out _ ); - return new RuntimeInfo (RuntimeKind.NetCore) { RuntimeDir = runtimeDir, RefAssembliesDir = refAssembliesDir, CscPath = MakeCscPath (sdkDir), MaxSupportedLangVersion = maxCSharpVersion, Version = hostVersion }; + return new RuntimeInfo (RuntimeKind.NetCore) { RuntimeDir = runtimeDir, RefAssembliesDir = refAssembliesDir, CscPath = cscPath, MaxSupportedLangVersion = maxCSharpVersion, Version = hostVersion }; } static string FindHighestVersionedDirectory (string parentFolder, Func validate, out SemVersion bestVersion) { + if (!Directory.Exists (parentFolder)) { + bestVersion = SemVersion.Zero; + return null; + } string bestMatch = null; bestVersion = SemVersion.Zero; foreach (var dir in Directory.EnumerateDirectories (parentFolder)) { From d84065e3081af2bf587b3855532d13ea034a89ee Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Mon, 6 Jun 2022 13:30:15 +0100 Subject: [PATCH 2/3] Roslyn compiler was not using the best supported C# lang version The CSharpParseOptions was not using the best language version. The CSharpParseOptions was created but no language version was used from the RuntimeInfo nor the language version specified by the Roslyn code compiler. --- .../RoslynCodeCompiler.cs | 18 ++++++++++++------ .../TemplatingEngineExtension.cs | 1 - .../CSharpLangVersionHelper.cs | 2 +- .../RuntimeInfo.cs | 7 +------ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Mono.TextTemplating.Roslyn/RoslynCodeCompiler.cs b/Mono.TextTemplating.Roslyn/RoslynCodeCompiler.cs index 4ab9a01..13613ab 100644 --- a/Mono.TextTemplating.Roslyn/RoslynCodeCompiler.cs +++ b/Mono.TextTemplating.Roslyn/RoslynCodeCompiler.cs @@ -53,14 +53,11 @@ CodeCompilerResult CompileFileInternal ( var parseOptions = args?.ParseOptions ?? new CSharpParseOptions(); if (arguments.LangVersion != null) { - if (LanguageVersionFacts.TryParse(arguments.LangVersion, out var langVersion)) { - parseOptions = parseOptions.WithLanguageVersion (langVersion); - } else { - throw new System.Exception($"Unknown value '{arguments.LangVersion}' for langversion"); - } + parseOptions = WithLanguageVersion (parseOptions, arguments.LangVersion); } else { // need to update this when updating referenced roslyn binaries - CSharpLangVersionHelper.GetBestSupportedLangVersion (runtime, CSharpLangVersion.v9_0); + var langVersion = CSharpLangVersionHelper.GetBestSupportedLangVersion (runtime, CSharpLangVersion.v9_0); + parseOptions = WithLanguageVersion (parseOptions, CSharpLangVersionHelper.ToString (langVersion)); } var syntaxTrees = new List (); @@ -120,5 +117,14 @@ CodeCompilerResult CompileFileInternal ( Errors = errors }; } + + static CSharpParseOptions WithLanguageVersion (CSharpParseOptions parseOptions, string langVersionText) + { + if (LanguageVersionFacts.TryParse (langVersionText, out var langVersion)) { + return parseOptions.WithLanguageVersion (langVersion); + } else { + throw new System.Exception ($"Unknown value '{langVersionText}' for langversion"); + } + } } } \ No newline at end of file diff --git a/Mono.TextTemplating.Roslyn/TemplatingEngineExtension.cs b/Mono.TextTemplating.Roslyn/TemplatingEngineExtension.cs index 8ca6d8e..ba7f312 100644 --- a/Mono.TextTemplating.Roslyn/TemplatingEngineExtension.cs +++ b/Mono.TextTemplating.Roslyn/TemplatingEngineExtension.cs @@ -11,7 +11,6 @@ public static void UseInProcessCompiler (this TemplatingEngine engine) engine.SetCompilerFunc ((RuntimeInfo r) => new RoslynCodeCompiler (r)); RuntimeInfo.ThrowOnMissingDotNetCoreSdkDirectory = false; - RuntimeInfo.DefaultMaxSupportedLangVersion = CSharpLangVersion.v9_0; } public static void UseInProcessCompiler (this TemplateGenerator generator) diff --git a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersionHelper.cs b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersionHelper.cs index 1e911d2..c1f7365 100644 --- a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersionHelper.cs +++ b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/CSharpLangVersionHelper.cs @@ -36,7 +36,7 @@ static bool HasLangVersionArg (string args) => && ProcessArgumentBuilder.TryParse (args, out var parsedArgs) && parsedArgs.Any (a => a.IndexOf("langversion") == 1); - static string ToString (CSharpLangVersion v) => v switch { + internal static string ToString (CSharpLangVersion v) => v switch { CSharpLangVersion.v5_0 => "5", CSharpLangVersion.v6_0 => "6", CSharpLangVersion.v7_0 => "7", diff --git a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs index fb6b082..7d1134f 100644 --- a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs +++ b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs @@ -142,12 +142,7 @@ static RuntimeInfo GetDotNetCoreSdk () return FromError (RuntimeKind.NetCore, "Could not find csc.dll in any .NET Core SDK"); } string cscPath = sdkDir == null ? null : MakeCscPath (sdkDir); - CSharpLangVersion maxCSharpVersion; - if (sdkVersion.Equals(SemVersion.Zero) && DefaultMaxSupportedLangVersion.HasValue) { - maxCSharpVersion = DefaultMaxSupportedLangVersion.Value; - } else { - maxCSharpVersion = CSharpLangVersionHelper.FromNetCoreSdkVersion (sdkVersion); - } + CSharpLangVersion maxCSharpVersion = CSharpLangVersionHelper.FromNetCoreSdkVersion (sdkVersion); // it's ok if this is null, we may be running on an older SDK that didn't support packs //in which case we fall back to resolving from the runtime dir From c411b6afec7bab51825954907b8b92b9a775d4e8 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Mon, 6 Jun 2022 15:51:28 +0100 Subject: [PATCH 3/3] Remove unused DefaultMaxSupportedLangVersion property Not needed on the RuntimeInfo class anymore. --- .../Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs index 7d1134f..675a21e 100644 --- a/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs +++ b/Mono.TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs @@ -57,7 +57,6 @@ class RuntimeInfo public string RuntimeFacadesDir { get; internal set; } internal static bool ThrowOnMissingDotNetCoreSdkDirectory { get; set; } = true; - internal static CSharpLangVersion? DefaultMaxSupportedLangVersion { get; set; } public static RuntimeInfo GetRuntime () {