From d23b6505892efe8e56aa267a2a2c698fb0920c67 Mon Sep 17 00:00:00 2001 From: walterlv Date: Mon, 20 May 2024 17:17:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=85=A5=20MSBuild=20API=20=E4=BB=A5?= =?UTF-8?q?=E5=88=86=E5=88=AB=E4=BD=BF=E7=94=A8=E6=BA=90=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E5=92=8C=E5=BA=93=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...LoggerSample.LoggerDependentLibrary.csproj | 1 - ...ggerSample.LoggerIndependentLibrary.csproj | 2 +- .../SourceReferenceTarget.cs | 4 +- ...ggerSample.LoggerIndependentProject.csproj | 2 +- .../SourceReferenceTarget.cs | 4 +- .../LoggerSample.MainApp.csproj | 4 +- samples/LoggerSample.MainApp/Program.cs | 2 - .../Generators/GlobalUsingsGenerator.cs | 30 ++++--- .../Generators/LoggerGenerator.cs | 13 ++- .../AnalyzerConfigOptionsExtensions.cs | 87 +++++++++++++++++++ .../Properties/Package/build/Package.props | 21 +++-- .../Properties/Package/build/Package.targets | 51 ++++++++++- 12 files changed, 190 insertions(+), 31 deletions(-) create mode 100644 src/dotnetCampus.Logger.Analyzer/Utils/CodeAnalysis/AnalyzerConfigOptionsExtensions.cs diff --git a/samples/LoggerSample.LoggerDependentLibrary/LoggerSample.LoggerDependentLibrary.csproj b/samples/LoggerSample.LoggerDependentLibrary/LoggerSample.LoggerDependentLibrary.csproj index 2db8c72..8b1387f 100644 --- a/samples/LoggerSample.LoggerDependentLibrary/LoggerSample.LoggerDependentLibrary.csproj +++ b/samples/LoggerSample.LoggerDependentLibrary/LoggerSample.LoggerDependentLibrary.csproj @@ -5,7 +5,6 @@ net8.0 enable - <_DLMainlyUseGeneratedLogger>false diff --git a/samples/LoggerSample.LoggerIndependentLibrary/LoggerSample.LoggerIndependentLibrary.csproj b/samples/LoggerSample.LoggerIndependentLibrary/LoggerSample.LoggerIndependentLibrary.csproj index dc27bd5..2410b13 100644 --- a/samples/LoggerSample.LoggerIndependentLibrary/LoggerSample.LoggerIndependentLibrary.csproj +++ b/samples/LoggerSample.LoggerIndependentLibrary/LoggerSample.LoggerIndependentLibrary.csproj @@ -5,7 +5,7 @@ net8.0 enable - <_DLMainlyUseGeneratedLogger>true + true diff --git a/samples/LoggerSample.LoggerIndependentLibrary/SourceReferenceTarget.cs b/samples/LoggerSample.LoggerIndependentLibrary/SourceReferenceTarget.cs index 7e8e077..72923f2 100644 --- a/samples/LoggerSample.LoggerIndependentLibrary/SourceReferenceTarget.cs +++ b/samples/LoggerSample.LoggerIndependentLibrary/SourceReferenceTarget.cs @@ -1,4 +1,6 @@ -namespace LoggerSample.LoggerIndependentLibrary; +using LoggerSample.LoggerIndependentLibrary.Logging; + +namespace LoggerSample.LoggerIndependentLibrary; public static class SourceReferenceTarget { diff --git a/samples/LoggerSample.LoggerIndependentProject/LoggerSample.LoggerIndependentProject.csproj b/samples/LoggerSample.LoggerIndependentProject/LoggerSample.LoggerIndependentProject.csproj index dc27bd5..2410b13 100644 --- a/samples/LoggerSample.LoggerIndependentProject/LoggerSample.LoggerIndependentProject.csproj +++ b/samples/LoggerSample.LoggerIndependentProject/LoggerSample.LoggerIndependentProject.csproj @@ -5,7 +5,7 @@ net8.0 enable - <_DLMainlyUseGeneratedLogger>true + true diff --git a/samples/LoggerSample.LoggerIndependentProject/SourceReferenceTarget.cs b/samples/LoggerSample.LoggerIndependentProject/SourceReferenceTarget.cs index 4b2f358..4536fa0 100644 --- a/samples/LoggerSample.LoggerIndependentProject/SourceReferenceTarget.cs +++ b/samples/LoggerSample.LoggerIndependentProject/SourceReferenceTarget.cs @@ -1,4 +1,6 @@ -namespace LoggerSample.LoggerIndependentProject; +using LoggerSample.LoggerIndependentProject.Logging; + +namespace LoggerSample.LoggerIndependentProject; public class SourceReferenceTarget { diff --git a/samples/LoggerSample.MainApp/LoggerSample.MainApp.csproj b/samples/LoggerSample.MainApp/LoggerSample.MainApp.csproj index b18f10b..c34714d 100644 --- a/samples/LoggerSample.MainApp/LoggerSample.MainApp.csproj +++ b/samples/LoggerSample.MainApp/LoggerSample.MainApp.csproj @@ -5,12 +5,12 @@ WinExe net8.0 - <_DLMainlyUseGeneratedLogger>false + preferReference - + diff --git a/samples/LoggerSample.MainApp/Program.cs b/samples/LoggerSample.MainApp/Program.cs index a7f15a3..d3684d8 100644 --- a/samples/LoggerSample.MainApp/Program.cs +++ b/samples/LoggerSample.MainApp/Program.cs @@ -1,7 +1,6 @@ using dotnetCampus.Logging.Attributes; using dotnetCampus.Logging.Configurations; using dotnetCampus.Logging.Writers; -using LoggerSample.MainApp.Logging; namespace LoggerSample.MainApp; @@ -37,5 +36,4 @@ public static void Main(string[] args) [ImportLoggerBridge] [ImportLoggerBridge] -[ImportLoggerBridge] internal partial class LoggerBridgeLinker; diff --git a/src/dotnetCampus.Logger.Analyzer/Generators/GlobalUsingsGenerator.cs b/src/dotnetCampus.Logger.Analyzer/Generators/GlobalUsingsGenerator.cs index 75b274e..e2b512e 100644 --- a/src/dotnetCampus.Logger.Analyzer/Generators/GlobalUsingsGenerator.cs +++ b/src/dotnetCampus.Logger.Analyzer/Generators/GlobalUsingsGenerator.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Immutable; -using System.Diagnostics; +using System.Collections.Immutable; using System.Linq; using System.Text; using dotnetCampus.Logger.Utils.CodeAnalysis; @@ -24,19 +22,26 @@ public void Initialize(IncrementalGeneratorInitializationContext context) private void Execute(SourceProductionContext context, AnalyzerConfigOptionsProvider provider) { - provider.GlobalOptions.TryGetValue("build_property.OutputType", out var outputType); - provider.GlobalOptions.TryGetValue("build_property.RootNamespace", out var rootNamespace); - provider.GlobalOptions.TryGetValue("build_property._DLMainlyUseGeneratedLogger", out var mainlyUseGeneratedLogger); - if (outputType is null || rootNamespace is null || mainlyUseGeneratedLogger is null) + if (provider.GlobalOptions + .TryGetValue("_DLRootNamespace", out var rootNamespace) + .TryGetValue("_DLGenerateSource", out var generateSource) + .TryGetValue("_DLGenerateGlobalUsings", out var generateGlobalUsings) + .TryGetValue("_DLPreferGeneratedSource", out var preferGeneratedSource) + is var result + && !result) { - context.ReportUnknownError("NuGet 包中应包含 OutputType、RootNamespace 和 _DLMainlyUseGeneratedLogger 属性。"); + // 此项目是通过依赖间接引用的,没有 build 因此无法在源生成器中使用编译属性,所以只能选择引用。 return; } - var useGeneratedLogger = mainlyUseGeneratedLogger.Equals("true", StringComparison.OrdinalIgnoreCase); - var generatedCode = useGeneratedLogger - ? GenerateGlobalUsings(rootNamespace, useGeneratedLogger) - : GenerateGlobalUsings("dotnetCampus", useGeneratedLogger); + if (!generateSource || !generateGlobalUsings) + { + return; + } + + var generatedCode = preferGeneratedSource + ? GenerateGlobalUsings(rootNamespace, preferGeneratedSource) + : GenerateGlobalUsings("dotnetCampus", preferGeneratedSource); context.AddSource("GlobalUsings.g.cs", SourceText.From(generatedCode, Encoding.UTF8)); } @@ -66,7 +71,6 @@ private string GenerateGlobalUsingsForTypes(string rootNamespace, ImmutableArray if ( // 如果使用源生成器的日志系统,则所有类型均要导出全局引用。 useGeneratedLogger - // 如果使用源生成器的日志系统,则所有类型均要导出全局引用。 || sourceFile.Namespace.EndsWith("Sources") ) { diff --git a/src/dotnetCampus.Logger.Analyzer/Generators/LoggerGenerator.cs b/src/dotnetCampus.Logger.Analyzer/Generators/LoggerGenerator.cs index d4615f5..36460f0 100644 --- a/src/dotnetCampus.Logger.Analyzer/Generators/LoggerGenerator.cs +++ b/src/dotnetCampus.Logger.Analyzer/Generators/LoggerGenerator.cs @@ -2,6 +2,7 @@ using System.Collections.Immutable; using System.Text; using System.Text.RegularExpressions; +using dotnetCampus.Logger.Utils.CodeAnalysis; using dotnetCampus.Logger.Utils.IO; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -23,7 +24,17 @@ public void Initialize(IncrementalGeneratorInitializationContext context) private void Execute(SourceProductionContext context, AnalyzerConfigOptionsProvider provider) { - if (!provider.GlobalOptions.TryGetValue("build_property.RootNamespace", out var rootNamespace)) + if (provider.GlobalOptions + .TryGetValue("_DLRootNamespace", out var rootNamespace) + .TryGetValue("_DLGenerateSource", out var isGenerateSource) + is var result + && !result) + { + // 此项目是通过依赖间接引用的,没有 build 因此无法在源生成器中使用编译属性,所以只能选择引用。 + return; + } + + if (!isGenerateSource) { return; } diff --git a/src/dotnetCampus.Logger.Analyzer/Utils/CodeAnalysis/AnalyzerConfigOptionsExtensions.cs b/src/dotnetCampus.Logger.Analyzer/Utils/CodeAnalysis/AnalyzerConfigOptionsExtensions.cs new file mode 100644 index 0000000..1ec7b40 --- /dev/null +++ b/src/dotnetCampus.Logger.Analyzer/Utils/CodeAnalysis/AnalyzerConfigOptionsExtensions.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace dotnetCampus.Logger.Utils.CodeAnalysis; + +internal static class AnalyzerConfigOptionsExtensions +{ + public static AnalyzerConfigOptionResult TryGetValue( + this AnalyzerConfigOptions options, + string key, + out T value) + where T : notnull + { + if (options.TryGetValue($"build_property.{key}", out var stringValue)) + { + value = ConvertFromString(stringValue); + return new AnalyzerConfigOptionResult(options, true) + { + UnsetPropertyNames = [], + }; + } + + value = default!; + return new AnalyzerConfigOptionResult(options, false) + { + UnsetPropertyNames = [key], + }; + } + + public static AnalyzerConfigOptionResult TryGetValue( + this AnalyzerConfigOptionResult builder, + string key, + out T value) + where T : notnull + { + var options = builder.Options; + + if (options.TryGetValue($"build_property.{key}", out var stringValue)) + { + value = ConvertFromString(stringValue); + return builder.Link(true, key); + } + + value = default!; + return builder.Link(false, key); + } + + private static T ConvertFromString(string value) + { + if (typeof(T) == typeof(string)) + { + return (T)(object)value; + } + if (typeof(T) == typeof(bool)) + { + return (T)(object)value.Equals("true", StringComparison.OrdinalIgnoreCase); + } + return default!; + } +} + +public readonly record struct AnalyzerConfigOptionResult(AnalyzerConfigOptions Options, bool GotValue) +{ + public required ImmutableList UnsetPropertyNames { get; init; } + + public AnalyzerConfigOptionResult Link(bool result, string propertyName) + { + if (result) + { + return this; + } + + if (propertyName is null) + { + throw new ArgumentNullException(nameof(propertyName), @"The property name must be specified if the result is false."); + } + + return this with + { + GotValue = false, + UnsetPropertyNames = UnsetPropertyNames.Add(propertyName), + }; + } + + public static implicit operator bool(AnalyzerConfigOptionResult result) => result.GotValue; +} diff --git a/src/dotnetCampus.Logger/Properties/Package/build/Package.props b/src/dotnetCampus.Logger/Properties/Package/build/Package.props index 3e9cfa9..33e458d 100644 --- a/src/dotnetCampus.Logger/Properties/Package/build/Package.props +++ b/src/dotnetCampus.Logger/Properties/Package/build/Package.props @@ -4,10 +4,21 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - + + + + + diff --git a/src/dotnetCampus.Logger/Properties/Package/build/Package.targets b/src/dotnetCampus.Logger/Properties/Package/build/Package.targets index 2a50c46..e830c51 100644 --- a/src/dotnetCampus.Logger/Properties/Package/build/Package.targets +++ b/src/dotnetCampus.Logger/Properties/Package/build/Package.targets @@ -4,9 +4,54 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - <_DLMainlyUseGeneratedLogger Condition="$(OutputType) != 'Exe' and $(OutputType) != 'WinExe'">true + + + onlyReference + + + <_DLGenerateSource>true + <_DLGenerateGlobalUsings>false + <_DLPreferGeneratedSource>true + + + + + + + + + + <_DLGenerateSource>true + <_DLGenerateGlobalUsings>true + <_DLPreferGeneratedSource>true + + + + + <_DLGenerateSource>true + <_DLGenerateGlobalUsings>true + <_DLPreferGeneratedSource>false + + + + + <_DLGenerateSource Condition=" '$(_DLGenerateSource)' == '' ">false + <_DLGenerateGlobalUsings Condition=" '$(_DLGenerateGlobalUsings)' == '' ">false + <_DLPreferGeneratedSource Condition=" '$(_DLPreferGeneratedSource)' == '' ">false + + + + <_DLRootNamespace>$(RootNamespace) + <_DLRootNamespace Condition=" '$(_DLRootNamespace)' == '' ">$(MSBuildProjectName.Replace(" ", "_")) + + + + + + + + +