Skip to content

Commit

Permalink
加入 MSBuild API 以分别使用源引用和库引用
Browse files Browse the repository at this point in the history
  • Loading branch information
walterlv committed May 20, 2024
1 parent 3273299 commit d23b650
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<_DLMainlyUseGeneratedLogger>false</_DLMainlyUseGeneratedLogger>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<_DLMainlyUseGeneratedLogger>true</_DLMainlyUseGeneratedLogger>
<DCUseGeneratedLogger>true</DCUseGeneratedLogger>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace LoggerSample.LoggerIndependentLibrary;
using LoggerSample.LoggerIndependentLibrary.Logging;

namespace LoggerSample.LoggerIndependentLibrary;

public static class SourceReferenceTarget
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<_DLMainlyUseGeneratedLogger>true</_DLMainlyUseGeneratedLogger>
<DCUseGeneratedLogger>true</DCUseGeneratedLogger>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace LoggerSample.LoggerIndependentProject;
using LoggerSample.LoggerIndependentProject.Logging;

namespace LoggerSample.LoggerIndependentProject;

public class SourceReferenceTarget
{
Expand Down
4 changes: 2 additions & 2 deletions samples/LoggerSample.MainApp/LoggerSample.MainApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<_DLMainlyUseGeneratedLogger>false</_DLMainlyUseGeneratedLogger>
<DCUseGeneratedLogger>preferReference</DCUseGeneratedLogger>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\dotnetCampus.Logger.Analyzer\dotnetCampus.Logger.Analyzer.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\src\dotnetCampus.Logger\dotnetCampus.Logger.csproj" />
<ProjectReference Include="..\..\src\dotnetCampus.Logger\dotnetCampus.Logger.csproj" OutputItemType="xxxxxxxxxx" />
<ProjectReference Include="..\LoggerSample.LoggerDependentLibrary\LoggerSample.LoggerDependentLibrary.csproj" />
<ProjectReference Include="..\LoggerSample.LoggerIndependentLibrary\LoggerSample.LoggerIndependentLibrary.csproj" />
<ProjectReference Include="..\LoggerSample.LoggerIndependentProject\LoggerSample.LoggerIndependentProject.csproj" />
Expand Down
2 changes: 0 additions & 2 deletions samples/LoggerSample.MainApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using dotnetCampus.Logging.Attributes;
using dotnetCampus.Logging.Configurations;
using dotnetCampus.Logging.Writers;
using LoggerSample.MainApp.Logging;

namespace LoggerSample.MainApp;

Expand Down Expand Up @@ -37,5 +36,4 @@ public static void Main(string[] args)

[ImportLoggerBridge<global::LoggerSample.LoggerIndependentLibrary.Logging.ILoggerBridge>]
[ImportLoggerBridge<global::LoggerSample.LoggerIndependentProject.Logging.ILoggerBridge>]
[ImportLoggerBridge<global::LoggerSample.MainApp.Logging.ILoggerBridge>]
internal partial class LoggerBridgeLinker;
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<string>("_DLRootNamespace", out var rootNamespace)
.TryGetValue<bool>("_DLGenerateSource", out var generateSource)
.TryGetValue<bool>("_DLGenerateGlobalUsings", out var generateGlobalUsings)
.TryGetValue<bool>("_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));
}
Expand Down Expand Up @@ -66,7 +71,6 @@ private string GenerateGlobalUsingsForTypes(string rootNamespace, ImmutableArray
if (
// 如果使用源生成器的日志系统,则所有类型均要导出全局引用。
useGeneratedLogger
// 如果使用源生成器的日志系统,则所有类型均要导出全局引用。
|| sourceFile.Namespace.EndsWith("Sources")
)
{
Expand Down
13 changes: 12 additions & 1 deletion src/dotnetCampus.Logger.Analyzer/Generators/LoggerGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<string>("_DLRootNamespace", out var rootNamespace)
.TryGetValue<bool>("_DLGenerateSource", out var isGenerateSource)
is var result
&& !result)
{
// 此项目是通过依赖间接引用的,没有 build 因此无法在源生成器中使用编译属性,所以只能选择引用。
return;
}

if (!isGenerateSource)
{
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<T>(
this AnalyzerConfigOptions options,
string key,
out T value)
where T : notnull
{
if (options.TryGetValue($"build_property.{key}", out var stringValue))
{
value = ConvertFromString<T>(stringValue);
return new AnalyzerConfigOptionResult(options, true)
{
UnsetPropertyNames = [],
};
}

value = default!;
return new AnalyzerConfigOptionResult(options, false)
{
UnsetPropertyNames = [key],
};
}

public static AnalyzerConfigOptionResult TryGetValue<T>(
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<T>(stringValue);
return builder.Link(true, key);
}

value = default!;
return builder.Link(false, key);
}

private static T ConvertFromString<T>(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<string> 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;
}
21 changes: 16 additions & 5 deletions src/dotnetCampus.Logger/Properties/Package/build/Package.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,21 @@
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>

<ItemGroup>
<CompilerVisibleProperty Include="RootNamespace" />
<CompilerVisibleProperty Include="OutputType" />
<CompilerVisibleProperty Include="_DLMainlyUseGeneratedLogger" />
</ItemGroup>
<PropertyGroup>
<!--
值:
- onlySource: 只使用源生成器日志系统,不会引用库;
- preferSource: 使用源生成器日志系统,并优先使用它;
- preferReference: 使用源生成器日志系统,但优先使用引用的库;
- onlyReference: 只使用引用的库,不会生成源代码;
- true: 只使用源生成器日志系统,不会引用库(其含义与 onlySource 等同);
- false: 只使用引用的库,不会生成源代码(其含义与 onlyReference 等同)。
解释:
- 所谓优先,指的是生成 global usings 以指定优先级;
-->
<DCUseGeneratedLogger>
</DCUseGeneratedLogger>
</PropertyGroup>

</Project>
51 changes: 48 additions & 3 deletions src/dotnetCampus.Logger/Properties/Package/build/Package.targets
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,54 @@
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>

<PropertyGroup Condition="$(_DLMainlyUseGeneratedLogger) == ''">
<!-- 对于库项目,优先使用源生成器日志系统 -->
<_DLMainlyUseGeneratedLogger Condition="$(OutputType) != 'Exe' and $(OutputType) != 'WinExe'">true</_DLMainlyUseGeneratedLogger>
<!-- DCUseGeneratedLogger = null -->
<PropertyGroup Condition=" '$(DCUseGeneratedLogger)' == '' ">
<DCUseGeneratedLogger>onlyReference</DCUseGeneratedLogger>
</PropertyGroup>

<!-- DCUseGeneratedLogger = onlySource / true -->
<PropertyGroup Condition=" '$(DCUseGeneratedLogger)' == 'onlySource' or '$(DCUseGeneratedLogger)' == 'true' ">
<_DLGenerateSource>true</_DLGenerateSource>
<_DLGenerateGlobalUsings>false</_DLGenerateGlobalUsings>
<_DLPreferGeneratedSource>true</_DLPreferGeneratedSource>
</PropertyGroup>

<!-- DCUseGeneratedLogger = onlySource / true -->
<ItemGroup Condition=" '$(DCUseGeneratedLogger)' == 'onlySource' or '$(DCUseGeneratedLogger)' == 'true' ">
<PackageReference Update="dotnetCampus.Logger" PrivateAssets="all" />
</ItemGroup>

<!-- DCUseGeneratedLogger = preferSource -->
<PropertyGroup Condition=" '$(DCUseGeneratedLogger)' == 'preferSource' ">
<_DLGenerateSource>true</_DLGenerateSource>
<_DLGenerateGlobalUsings>true</_DLGenerateGlobalUsings>
<_DLPreferGeneratedSource>true</_DLPreferGeneratedSource>
</PropertyGroup>

<!-- DCUseGeneratedLogger = preferReference -->
<PropertyGroup Condition=" '$(DCUseGeneratedLogger)' == 'preferReference' ">
<_DLGenerateSource>true</_DLGenerateSource>
<_DLGenerateGlobalUsings>true</_DLGenerateGlobalUsings>
<_DLPreferGeneratedSource>false</_DLPreferGeneratedSource>
</PropertyGroup>

<!-- DCUseGeneratedLogger = onlyReference / false / 其他值 -->
<PropertyGroup>
<_DLGenerateSource Condition=" '$(_DLGenerateSource)' == '' ">false</_DLGenerateSource>
<_DLGenerateGlobalUsings Condition=" '$(_DLGenerateGlobalUsings)' == '' ">false</_DLGenerateGlobalUsings>
<_DLPreferGeneratedSource Condition=" '$(_DLPreferGeneratedSource)' == '' ">false</_DLPreferGeneratedSource>
</PropertyGroup>

<PropertyGroup>
<_DLRootNamespace>$(RootNamespace)</_DLRootNamespace>
<_DLRootNamespace Condition=" '$(_DLRootNamespace)' == '' ">$(MSBuildProjectName.Replace(" ", "_"))</_DLRootNamespace>
</PropertyGroup>

<ItemGroup>
<CompilerVisibleProperty Include="_DLGenerateSource" />
<CompilerVisibleProperty Include="_DLGenerateGlobalUsings" />
<CompilerVisibleProperty Include="_DLPreferGeneratedSource" />
<CompilerVisibleProperty Include="_DLRootNamespace" />
</ItemGroup>

</Project>

0 comments on commit d23b650

Please sign in to comment.