mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-25 21:34:28 +08:00
Merge pull request #135 from GeWuYou/feat/build-modular-global-usings
Feat/build modular global usings
This commit is contained in:
commit
b3d52a0865
171
Directory.Build.targets
Normal file
171
Directory.Build.targets
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
<Project>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
为 GFramework 运行时包生成可选的模块级 transitive global usings。
|
||||||
|
该逻辑只在明确启用的可打包项目中生效,并在构建/打包期间自动扫描源码命名空间。
|
||||||
|
-->
|
||||||
|
<UsingTask TaskName="GenerateGFrameworkTransitiveGlobalUsingsProps"
|
||||||
|
TaskFactory="RoslynCodeTaskFactory"
|
||||||
|
AssemblyFile="$(MSBuildToolsPath)/Microsoft.Build.Tasks.Core.dll">
|
||||||
|
<ParameterGroup>
|
||||||
|
<SourceFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true"/>
|
||||||
|
<ExcludedNamespaces ParameterType="Microsoft.Build.Framework.ITaskItem[]"/>
|
||||||
|
<ExcludedNamespacePrefixes ParameterType="Microsoft.Build.Framework.ITaskItem[]"/>
|
||||||
|
<OutputFile ParameterType="System.String" Required="true"/>
|
||||||
|
<NamespaceItemName ParameterType="System.String" Required="true"/>
|
||||||
|
</ParameterGroup>
|
||||||
|
<Task>
|
||||||
|
<Code Type="Fragment"
|
||||||
|
Language="cs"><![CDATA[
|
||||||
|
var discoveredNamespaces = new global::System.Collections.Generic.SortedSet<string>(global::System.StringComparer.Ordinal);
|
||||||
|
var exactExclusions = new global::System.Collections.Generic.HashSet<string>(global::System.StringComparer.Ordinal);
|
||||||
|
var prefixExclusions = new global::System.Collections.Generic.List<string>();
|
||||||
|
var namespacePattern = new global::System.Text.RegularExpressions.Regex(
|
||||||
|
@"^\s*namespace\s+([A-Za-z_][A-Za-z0-9_.]*)\s*(?:;|\{)",
|
||||||
|
global::System.Text.RegularExpressions.RegexOptions.Compiled);
|
||||||
|
|
||||||
|
if (ExcludedNamespaces != null)
|
||||||
|
{
|
||||||
|
foreach (var excludedNamespace in ExcludedNamespaces)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(excludedNamespace.ItemSpec))
|
||||||
|
{
|
||||||
|
exactExclusions.Add(excludedNamespace.ItemSpec.Trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExcludedNamespacePrefixes != null)
|
||||||
|
{
|
||||||
|
foreach (var excludedPrefix in ExcludedNamespacePrefixes)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(excludedPrefix.ItemSpec))
|
||||||
|
{
|
||||||
|
prefixExclusions.Add(excludedPrefix.ItemSpec.Trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var sourceFile in SourceFiles)
|
||||||
|
{
|
||||||
|
var path = sourceFile.ItemSpec;
|
||||||
|
if (!global::System.IO.File.Exists(path))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var line in global::System.IO.File.ReadLines(path))
|
||||||
|
{
|
||||||
|
var match = namespacePattern.Match(line);
|
||||||
|
if (!match.Success)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var namespaceName = match.Groups[1].Value;
|
||||||
|
if (!namespaceName.StartsWith("GFramework.", global::System.StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exactExclusions.Contains(namespaceName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var excludedByPrefix = false;
|
||||||
|
foreach (var prefix in prefixExclusions)
|
||||||
|
{
|
||||||
|
if (namespaceName.StartsWith(prefix, global::System.StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
excludedByPrefix = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!excludedByPrefix)
|
||||||
|
{
|
||||||
|
discoveredNamespaces.Add(namespaceName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static string Escape(string value)
|
||||||
|
{
|
||||||
|
return global::System.Security.SecurityElement.Escape(value) ?? value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var directory = global::System.IO.Path.GetDirectoryName(OutputFile);
|
||||||
|
if (!string.IsNullOrEmpty(directory))
|
||||||
|
{
|
||||||
|
global::System.IO.Directory.CreateDirectory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new global::System.Text.StringBuilder();
|
||||||
|
var msbuildPropertyOpen = new string(new[] { '$', '(' });
|
||||||
|
var msbuildItemOpen = new string(new[] { '@', '(' });
|
||||||
|
builder.AppendLine("<Project>");
|
||||||
|
builder.AppendLine(" <!-- This file is generated by GFramework's MSBuild transitive global usings pipeline. -->");
|
||||||
|
builder.AppendLine(" <!-- EnableGFrameworkGlobalUsings=true enables the transitive global usings from this package. -->");
|
||||||
|
builder.AppendLine(" <!-- Add <GFrameworkExcludedUsing Include=\"Namespace\" /> to opt out of specific namespaces. -->");
|
||||||
|
builder.Append(" <ItemGroup Condition=\"'");
|
||||||
|
builder.Append(msbuildPropertyOpen);
|
||||||
|
builder.AppendLine("EnableGFrameworkGlobalUsings)' == 'true'\">");
|
||||||
|
|
||||||
|
foreach (var namespaceName in discoveredNamespaces)
|
||||||
|
{
|
||||||
|
builder.Append(" <");
|
||||||
|
builder.Append(NamespaceItemName);
|
||||||
|
builder.Append(" Include=\"");
|
||||||
|
builder.Append(Escape(namespaceName));
|
||||||
|
builder.AppendLine("\" />");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(" <");
|
||||||
|
builder.Append(NamespaceItemName);
|
||||||
|
builder.Append(" Remove=\"");
|
||||||
|
builder.Append(msbuildItemOpen);
|
||||||
|
builder.AppendLine("GFrameworkExcludedUsing)\" />");
|
||||||
|
builder.Append(" <Using Include=\"");
|
||||||
|
builder.Append(msbuildItemOpen);
|
||||||
|
builder.Append(NamespaceItemName);
|
||||||
|
builder.AppendLine(")\" />");
|
||||||
|
builder.AppendLine(" </ItemGroup>");
|
||||||
|
builder.AppendLine("</Project>");
|
||||||
|
|
||||||
|
global::System.IO.File.WriteAllText(OutputFile, builder.ToString(), new global::System.Text.UTF8Encoding(false));
|
||||||
|
Log.LogMessage(global::Microsoft.Build.Framework.MessageImportance.Low,
|
||||||
|
$"Generated {discoveredNamespaces.Count} transitive global usings for {OutputFile}.");
|
||||||
|
]]></Code>
|
||||||
|
</Task>
|
||||||
|
</UsingTask>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<_GFrameworkTransitiveGlobalUsingsEnabled Condition="'$(EnableGFrameworkPackageTransitiveGlobalUsings)' == 'true' and '$(IsPackable)' != 'false'">true</_GFrameworkTransitiveGlobalUsingsEnabled>
|
||||||
|
<_GFrameworkTransitiveGlobalUsingsPrimaryTargetFramework Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and '$(TargetFrameworks)' != ''">$([System.String]::Copy('$(TargetFrameworks)').Split(';')[0])</_GFrameworkTransitiveGlobalUsingsPrimaryTargetFramework>
|
||||||
|
<_GFrameworkTransitiveGlobalUsingsGenerationBuild Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and ('$(TargetFrameworks)' == '' or '$(TargetFramework)' == '$(_GFrameworkTransitiveGlobalUsingsPrimaryTargetFramework)')">true</_GFrameworkTransitiveGlobalUsingsGenerationBuild>
|
||||||
|
<_GFrameworkTransitiveGlobalUsingsPackageId Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and '$(PackageId)' != ''">$(PackageId)</_GFrameworkTransitiveGlobalUsingsPackageId>
|
||||||
|
<_GFrameworkTransitiveGlobalUsingsPackageId Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true' and '$(_GFrameworkTransitiveGlobalUsingsPackageId)' == ''">$(AssemblyName)</_GFrameworkTransitiveGlobalUsingsPackageId>
|
||||||
|
<_GFrameworkTransitiveGlobalUsingsOutputFile Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true'">$(BaseIntermediateOutputPath)gframework/$(_GFrameworkTransitiveGlobalUsingsPackageId).props</_GFrameworkTransitiveGlobalUsingsOutputFile>
|
||||||
|
<_GFrameworkTransitiveGlobalUsingsItemName Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true'">_$([System.Text.RegularExpressions.Regex]::Replace('$(MSBuildProjectName)', '[^A-Za-z0-9_]', '_'))_TransitiveUsing</_GFrameworkTransitiveGlobalUsingsItemName>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(_GFrameworkTransitiveGlobalUsingsEnabled)' == 'true'">
|
||||||
|
<None Include="$(_GFrameworkTransitiveGlobalUsingsOutputFile)"
|
||||||
|
Pack="true"
|
||||||
|
PackagePath="buildTransitive"
|
||||||
|
Visible="false"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="GenerateGFrameworkModuleTransitiveGlobalUsings"
|
||||||
|
Condition="'$(_GFrameworkTransitiveGlobalUsingsGenerationBuild)' == 'true'"
|
||||||
|
BeforeTargets="CoreCompile;GenerateNuspec">
|
||||||
|
<GenerateGFrameworkTransitiveGlobalUsingsProps
|
||||||
|
SourceFiles="@(Compile->'%(FullPath)')"
|
||||||
|
ExcludedNamespaces="@(GFrameworkTransitiveUsingExclude)"
|
||||||
|
ExcludedNamespacePrefixes="@(GFrameworkTransitiveUsingExcludePrefix)"
|
||||||
|
OutputFile="$(_GFrameworkTransitiveGlobalUsingsOutputFile)"
|
||||||
|
NamespaceItemName="$(_GFrameworkTransitiveGlobalUsingsItemName)"/>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@ -10,6 +10,7 @@
|
|||||||
<MeziantouPolyfill_IncludedPolyfills>T:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute</MeziantouPolyfill_IncludedPolyfills>
|
<MeziantouPolyfill_IncludedPolyfills>T:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute</MeziantouPolyfill_IncludedPolyfills>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<EnableGFrameworkPackageTransitiveGlobalUsings>true</EnableGFrameworkPackageTransitiveGlobalUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- 引入必要的命名空间 -->
|
<!-- 引入必要的命名空间 -->
|
||||||
|
|||||||
@ -0,0 +1,80 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using GFramework.Core.Architectures;
|
||||||
|
using GFramework.Core.Coroutine.Extensions;
|
||||||
|
|
||||||
|
namespace GFramework.Core.Tests.Packaging;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证运行时模块在构建期间会自动生成 transitive global usings 资产。
|
||||||
|
/// 该测试覆盖命名空间自动发现、框架侧过滤和消费者侧排除钩子的最终构建产物。
|
||||||
|
/// </summary>
|
||||||
|
[TestFixture]
|
||||||
|
public class TransitiveGlobalUsingsPackagingTests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 使用真实类型派生架构命名空间,避免测试断言和命名空间重构脱节。
|
||||||
|
/// </summary>
|
||||||
|
private static readonly string ArchitectureNamespace = typeof(Architecture).Namespace
|
||||||
|
?? throw new InvalidOperationException(
|
||||||
|
"Architecture namespace should not be null.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用真实类型派生扩展命名空间,避免对字面量命名空间字符串的重复维护。
|
||||||
|
/// </summary>
|
||||||
|
private static readonly string ExtensionsNamespace = typeof(ContextAwareEnvironmentExtensions).Namespace
|
||||||
|
?? throw new InvalidOperationException(
|
||||||
|
"Extensions namespace should not be null.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用真实类型派生协程扩展命名空间,确保断言和源码自动发现保持一致。
|
||||||
|
/// </summary>
|
||||||
|
private static readonly string CoroutineExtensionsNamespace = typeof(CoroutineExtensions).Namespace
|
||||||
|
?? throw new InvalidOperationException(
|
||||||
|
"Coroutine extensions namespace should not be null.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证 GFramework.Core 在构建后会生成 transitive global usings props,
|
||||||
|
/// 且 props 内容来自源码自动发现,并保留消费者侧排除机制。
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void CoreBuild_Should_Generate_AutoDiscovered_TransitiveGlobalUsingsProps()
|
||||||
|
{
|
||||||
|
var repositoryRoot = ResolveRepositoryRoot();
|
||||||
|
var propsPath = Path.Combine(
|
||||||
|
repositoryRoot,
|
||||||
|
"GFramework.Core",
|
||||||
|
"obj",
|
||||||
|
"gframework",
|
||||||
|
"GeWuYou.GFramework.Core.props");
|
||||||
|
|
||||||
|
Assert.That(File.Exists(propsPath), Is.True, $"Expected generated props to exist: {propsPath}");
|
||||||
|
var propsContent = File.ReadAllText(propsPath);
|
||||||
|
|
||||||
|
Assert.That(propsContent, Does.Contain(ExtensionsNamespace));
|
||||||
|
Assert.That(propsContent, Does.Contain(ArchitectureNamespace));
|
||||||
|
Assert.That(propsContent, Does.Contain(CoroutineExtensionsNamespace));
|
||||||
|
Assert.That(propsContent, Does.Contain("Remove=\"@(GFrameworkExcludedUsing)\""));
|
||||||
|
Assert.That(propsContent, Does.Not.Contain("System.Runtime.CompilerServices"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基于当前测试源文件的已知位置解析仓库根目录。
|
||||||
|
/// 这里不扫描解决方案文件,避免测试对仓库布局演进产生额外脆弱性。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourceFilePath">由编译器注入的当前测试源文件绝对路径。</param>
|
||||||
|
/// <returns>仓库根目录绝对路径。</returns>
|
||||||
|
private static string ResolveRepositoryRoot([CallerFilePath] string sourceFilePath = "")
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(sourceFilePath))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Caller file path is required to resolve the repository root.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var sourceDirectory = Path.GetDirectoryName(sourceFilePath)
|
||||||
|
?? throw new DirectoryNotFoundException(
|
||||||
|
$"Could not determine the directory for source file path: {sourceFilePath}");
|
||||||
|
|
||||||
|
return Path.GetFullPath(Path.Combine(sourceDirectory, "..", ".."));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@
|
|||||||
<ImplicitUsings>disable</ImplicitUsings>
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<EnableGFrameworkPackageTransitiveGlobalUsings>true</EnableGFrameworkPackageTransitiveGlobalUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\$(AssemblyName).Abstractions\$(AssemblyName).Abstractions.csproj"/>
|
<ProjectReference Include="..\$(AssemblyName).Abstractions\$(AssemblyName).Abstractions.csproj"/>
|
||||||
|
|||||||
@ -4,10 +4,10 @@
|
|||||||
<PackageId>GeWuYou.$(AssemblyName)</PackageId>
|
<PackageId>GeWuYou.$(AssemblyName)</PackageId>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<EnableGFrameworkPackageTransitiveGlobalUsings>true</EnableGFrameworkPackageTransitiveGlobalUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\GFramework.Core.Abstractions\GFramework.Core.Abstractions.csproj" PrivateAssets="all"/>
|
<ProjectReference Include="..\GFramework.Core.Abstractions\GFramework.Core.Abstractions.csproj" PrivateAssets="all"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||||
|
<EnableGFrameworkPackageTransitiveGlobalUsings>true</EnableGFrameworkPackageTransitiveGlobalUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -19,5 +20,4 @@
|
|||||||
<PackageReference Include="Arch" Version="2.1.0"/>
|
<PackageReference Include="Arch" Version="2.1.0"/>
|
||||||
<PackageReference Include="Arch.System" Version="1.1.0"/>
|
<PackageReference Include="Arch.System" Version="1.1.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
<MeziantouPolyfill_IncludedPolyfills>T:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute</MeziantouPolyfill_IncludedPolyfills>
|
<MeziantouPolyfill_IncludedPolyfills>T:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute</MeziantouPolyfill_IncludedPolyfills>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<EnableGFrameworkPackageTransitiveGlobalUsings>true</EnableGFrameworkPackageTransitiveGlobalUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\GFramework.Core.Abstractions\GFramework.Core.Abstractions.csproj"/>
|
<ProjectReference Include="..\GFramework.Core.Abstractions\GFramework.Core.Abstractions.csproj"/>
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
<ImplicitUsings>disable</ImplicitUsings>
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<EnableGFrameworkPackageTransitiveGlobalUsings>true</EnableGFrameworkPackageTransitiveGlobalUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj"/>
|
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj"/>
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<EnableGFrameworkPackageTransitiveGlobalUsings>true</EnableGFrameworkPackageTransitiveGlobalUsings>
|
||||||
<!-- Godot.SourceGenerators expects this property from Godot.NET.Sdk.
|
<!-- Godot.SourceGenerators expects this property from Godot.NET.Sdk.
|
||||||
Provide a safe default so source generators can run in plain SDK-style builds as well. -->
|
Provide a safe default so source generators can run in plain SDK-style builds as well. -->
|
||||||
<GodotProjectDir Condition="'$(GodotProjectDir)' == ''">$(MSBuildProjectDirectory)</GodotProjectDir>
|
<GodotProjectDir Condition="'$(GodotProjectDir)' == ''">$(MSBuildProjectDirectory)</GodotProjectDir>
|
||||||
|
|||||||
26
README.md
26
README.md
@ -72,6 +72,32 @@ dotnet add package GeWuYou.GFramework.Godot
|
|||||||
dotnet add package GeWuYou.GFramework.SourceGenerators
|
dotnet add package GeWuYou.GFramework.SourceGenerators
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 可选模块导入
|
||||||
|
|
||||||
|
发布后的运行时包支持可选的模块级自动导入,但默认关闭,避免在普通项目里无意污染命名空间。
|
||||||
|
|
||||||
|
在 NuGet 消费项目中显式开启:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnableGFrameworkGlobalUsings>true</EnableGFrameworkGlobalUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
```
|
||||||
|
|
||||||
|
启用后,项目已引用的 GFramework 运行时模块会通过 `buildTransitive` 自动注入其推荐命名空间。
|
||||||
|
|
||||||
|
如果某几个命名空间不想导入,可以局部排除:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<ItemGroup>
|
||||||
|
<GFrameworkExcludedUsing Include="GFramework.Core.Environment" />
|
||||||
|
<GFrameworkExcludedUsing Include="GFramework.Godot.Extensions" />
|
||||||
|
</ItemGroup>
|
||||||
|
```
|
||||||
|
|
||||||
|
> 该能力面向 NuGet 包消费场景。若你在本地解决方案中直接使用 `ProjectReference`,仍建议保留自己的 `GlobalUsings.cs` 或手写
|
||||||
|
`using`。
|
||||||
|
|
||||||
## 仓库结构
|
## 仓库结构
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
|||||||
@ -88,19 +88,28 @@ dotnet add package GeWuYou.GFramework.SourceGenerators
|
|||||||
|
|
||||||
### 1. 基础配置
|
### 1. 基础配置
|
||||||
|
|
||||||
创建 `GlobalUsings.cs` 文件:
|
如果你通过 NuGet 包使用 GFramework,并且希望自动导入已安装模块的推荐命名空间,可以在项目文件中显式开启:
|
||||||
|
|
||||||
```csharp
|
```xml
|
||||||
global using GFramework.Core;
|
<PropertyGroup>
|
||||||
global using GFramework.Core.Architecture;
|
<EnableGFrameworkGlobalUsings>true</EnableGFrameworkGlobalUsings>
|
||||||
global using GFramework.Core.Command;
|
</PropertyGroup>
|
||||||
global using GFramework.Core.Events;
|
|
||||||
global using GFramework.Core.Model;
|
|
||||||
global using GFramework.Core.Property;
|
|
||||||
global using GFramework.Core.System;
|
|
||||||
global using GFramework.Core.Utility;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
启用后,当前项目已引用的 GFramework 运行时模块会通过 `buildTransitive` 自动注入对应命名空间。
|
||||||
|
|
||||||
|
如果你想排除局部导入,可以继续在项目文件中添加排除项:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<GFrameworkExcludedUsing Include="GFramework.Core.Environment"/>
|
||||||
|
<GFrameworkExcludedUsing Include="GFramework.Godot.Extensions"/>
|
||||||
|
</ItemGroup>
|
||||||
|
```
|
||||||
|
|
||||||
|
如果你使用的是本地 `ProjectReference`,或者希望完全手动控制导入范围,仍然可以继续维护自己的 `GlobalUsings.cs` 文件。
|
||||||
|
|
||||||
### 2. Godot 项目配置
|
### 2. Godot 项目配置
|
||||||
|
|
||||||
如果使用 Godot 集成,需要在项目设置中启用 C# 支持:
|
如果使用 Godot 集成,需要在项目设置中启用 C# 支持:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user