Skip to content

Commit

Permalink
Use incremental build
Browse files Browse the repository at this point in the history
  • Loading branch information
aelij committed Nov 30, 2023
1 parent 9944e77 commit 9d2bd05
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 129 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,5 @@ __pycache__/
*.xsd.cs

*.binlog

.DS_Store
11 changes: 2 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,12 @@ Just add the package and define `InternalsAssemblyName` items with the assemblie
<ItemGroup>
<InternalsAssemblyName Include="AssemblyToGrantAccessTo1" />
<InternalsAssemblyName Include="AssemblyToGrantAccessTo2" />
<InternalsAssemblyExcludeTypeName Include="Namespace.TypeName" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="IgnoresAccessChecksToGenerator" Version="0.6.0" PrivateAssets="All" />
<PackageReference Include="IgnoresAccessChecksToGenerator" Version="0.7.0" PrivateAssets="All" />
</ItemGroup>

</Project>
```

By default, the build tasks replaces all method bodies with `throw null;`. To keep the original bodies, you can specify:

```xml
<PropertyGroup>
<InternalsAssemblyUseEmptyMethodBodies>false</InternalsAssemblyUseEmptyMethodBodies>
</PropertyGroup>
```
34 changes: 0 additions & 34 deletions src/Build/IgnoresAccessChecksToGenerator.targets

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<NuspecFile>IgnoresAccessChecksToGenerator.nuspec</NuspecFile>
<TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
<PackageId>IgnoresAccessChecksToGenerator</PackageId>
<Version>0.7.0</Version>
<DevelopmentDependency>true</DevelopmentDependency>
<Authors>Eli Arbel</Authors>
<RepositoryUrl>https://github.com/aelij/IgnoresAccessChecksToGenerator</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Description>Generates IgnoresAccessChecksTo attributes and reference assemblies to allow compile-time access to internals</Description>
<PackageTags>IgnoresAccessChecksToGenerator IgnoresAccessChecksTo IgnoresAccessChecksToAttribute internals</PackageTags>
<BuildOutputTargetFolder>tools/$(TargetFramework)</BuildOutputTargetFolder>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludePackageDependencies</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="15.1.1012" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<Content Include="build\*" PackagePath="build" />
</ItemGroup>

<Target Name="CopyRefsTarget" AfterTargets="AfterBuild">
<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="17.8.3" />
</ItemGroup>

<Target Name="IncludePackageDependencies">
<ItemGroup>
<CopyRefs Include="@(ReferencePath)" Condition=" '%(Filename)' == 'Mono.Cecil' " />
<BuildOutputInPackage Include="@(ReferencePath)" Condition=" '%(Filename)' == 'Mono.Cecil' " />
</ItemGroup>
<Copy SourceFiles="@(CopyRefs)" DestinationFolder="$(OutDir)" />
</Target>

</Project>

This file was deleted.

59 changes: 10 additions & 49 deletions src/IgnoresAccessChecksToGenerator.Tasks/PublicizeInternals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ namespace IgnoresAccessChecksToGenerator.Tasks
{
public class PublicizeInternals : Task
{
private static readonly char[] Semicolon = { ';' };

private readonly AssemblyResolver _resolver = new AssemblyResolver();

[Required]
Expand All @@ -23,18 +21,10 @@ public class PublicizeInternals : Task
[Required]
public string IntermediateOutputPath { get; set; }

public string ExcludeTypeNames { get; set; }

public bool UseEmptyMethodBodies { get; set; } = true;

[Output]
public ITaskItem[] TargetReferences { get; set; }

[Output]
public ITaskItem[] RemovedReferences { get; set; }
[Required]
public string GeneratedCodeFilePath { get; set; }

[Output]
public ITaskItem[] GeneratedCodeFiles { get; set; }
public ITaskItem[] ExcludeTypeNames { get; set; }

public override bool Execute()
{
Expand All @@ -47,6 +37,8 @@ public override bool Execute()
return true;
}

var excludedTypeNames = new HashSet<string>(AssemblyNames.Select(t => t.ItemSpec), StringComparer.OrdinalIgnoreCase);

var targetPath = IntermediateOutputPath;
Directory.CreateDirectory(targetPath);

Expand All @@ -58,37 +50,19 @@ public override bool Execute()
_resolver.AddSearchDirectory(assemblyPath);
}

var targetReferences = new List<ITaskItem>();
var removedReferences = new List<ITaskItem>();

foreach (var assembly in SourceReferences)
{
var assemblyPath = GetFullFilePath(targetPath, assembly.ItemSpec);
var assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
if (assemblyNames.Contains(assemblyName))
{
// ReSharper disable once AssignNullToNotNullAttribute
var targetAssemblyPath = Path.Combine(targetPath, Path.GetFileName(assemblyPath));

var targetAsemblyFileInfo = new FileInfo(targetAssemblyPath);
if (!targetAsemblyFileInfo.Exists || targetAsemblyFileInfo.Length == 0)
{
CreatePublicAssembly(assemblyPath, targetAssemblyPath);
Log.LogMessageFromText("Created publicized assembly at " + targetAssemblyPath, MessageImportance.Normal);
}
else
{
Log.LogMessageFromText("Publicized assembly already exists at " + targetAssemblyPath, MessageImportance.Low);
}

targetReferences.Add(new TaskItem(targetAssemblyPath));
removedReferences.Add(assembly);
CreatePublicAssembly(assemblyPath, targetAssemblyPath, excludedTypeNames);
Log.LogMessageFromText("Created publicized assembly at " + targetAssemblyPath, MessageImportance.Normal);
}
}

TargetReferences = targetReferences.ToArray();
RemovedReferences = removedReferences.ToArray();

return true;
}

Expand All @@ -109,24 +83,19 @@ public IgnoresAccessChecksToAttribute(string assemblyName)
}
}
}";
var filePath = Path.Combine(path, "IgnoresAccessChecksTo.cs");
File.WriteAllText(filePath, content);

GeneratedCodeFiles = new ITaskItem[] { new TaskItem(filePath) };
File.WriteAllText(GeneratedCodeFilePath, content);

Log.LogMessageFromText("Generated IgnoresAccessChecksTo attributes", MessageImportance.Low);
}

private void CreatePublicAssembly(string source, string target)
private void CreatePublicAssembly(string source, string target, HashSet<string> excludedTypeNames)
{
var types = ExcludeTypeNames == null ? Array.Empty<string>() : ExcludeTypeNames.Split(Semicolon);

var assembly = AssemblyDefinition.ReadAssembly(source,
new ReaderParameters { AssemblyResolver = _resolver });

foreach (var module in assembly.Modules)
{
foreach (var type in module.GetTypes().Where(type=>!types.Contains(type.FullName)))
foreach (var type in module.GetTypes().Where(type => !excludedTypeNames.Contains(type.FullName)))
{
if (!type.IsNested && type.IsNotPublic)
{
Expand All @@ -151,14 +120,6 @@ private void CreatePublicAssembly(string source, string target)

foreach (var method in type.Methods)
{
if (UseEmptyMethodBodies && method.HasBody)
{
var emptyBody = new Mono.Cecil.Cil.MethodBody(method);
emptyBody.Instructions.Add(Mono.Cecil.Cil.Instruction.Create(Mono.Cecil.Cil.OpCodes.Ldnull));
emptyBody.Instructions.Add(Mono.Cecil.Cil.Instruction.Create(Mono.Cecil.Cil.OpCodes.Throw));
method.Body = emptyBody;
}

if (method.IsAssembly ||
method.IsFamilyOrAssembly ||
method.IsFamilyAndAssembly)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
<InternalsAssemblyName>
<Visible>false</Visible>
</InternalsAssemblyName>
<InternalsAssemblyExcludeTypeName>
<Visible>false</Visible>
</InternalsAssemblyExcludeTypeName>
</ItemDefinitionGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<Project>

<PropertyGroup>
<_IACTG_TargetFramework Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0</_IACTG_TargetFramework>
<_IACTG_TargetFramework Condition="'$(MSBuildRuntimeType)' != 'Core'">net462</_IACTG_TargetFramework>
<_IACTG_TaskAssembly>$(MSBuildThisFileDirectory)../tools/$(_IACTG_TargetFramework)/IgnoresAccessChecksToGenerator.Tasks.dll</_IACTG_TaskAssembly>
<_IACTG_IntermediatePath>$(IntermediateOutputPath)/IgnoresAccessChecksToGenerator</_IACTG_IntermediatePath>
<_IACTG_CodeFilePath>$(_IACTG_IntermediatePath)/IgnoresAccessChecksTo.cs</_IACTG_CodeFilePath>
<_IACTG_ManifestFilePath>$(_IACTG_IntermediatePath)/IgnoresAccessChecksToGenerator.manifest</_IACTG_ManifestFilePath>
</PropertyGroup>

<UsingTask AssemblyFile="$(_IACTG_TaskAssembly)" TaskName="IgnoresAccessChecksToGenerator.Tasks.PublicizeInternals" />

<!--
MSBuild incremental build tracking only supports files, so we create a manifest that contains all the items we use as inputs.
This target has MSBuildAllProjects as input which means it will be invalidated on any project file change.
-->
<Target Name="GetIgnoresAccessChecksToGeneratorReferencePaths"
Inputs="$(MSBuildAllProjects)"
Outputs="$(_IACTG_ManifestFilePath)"
Returns="@(_IACTG_InputReferencePath);@(_IACTG_OutputReferencePath)">
<ItemGroup>
<InternalsAssemblyName Include="$(InternalsAssemblyNames.Split(;))" />
<InternalsAssemblyExcludeTypeName Include="$(InternalsAssemblyExcludeTypeNames.Split(;))" />
</ItemGroup>
<ItemGroup>
<_IACTG_ReferencePathJoin Include="@(ReferencePath)" InternalsAssemblyName="%(InternalsAssemblyName.Identity)" />
<_IACTG_InputReferencePath Include="@(_IACTG_ReferencePathJoin)" Condition=" '%(Filename)' == '%(InternalsAssemblyName)' " />
<_IACTG_ReferencePathJoin Remove="@(_IACTG_ReferencePathJoin)" />
<_IACTG_OutputReferencePath Include="@(_IACTG_InputReferencePath->'$(_IACTG_IntermediatePath)/%(Filename)%(Extension)')" OriginalItemSpec="%(Identity)" />
</ItemGroup>
<ItemGroup>
<_IACTG_Manifest Include="@(InternalsAssemblyExcludeTypeName)" />
</ItemGroup>
<WriteLinesToFile File="$(_IACTG_ManifestFilePath)" Lines="@(_IACTG_Manifest)" WriteOnlyWhenDifferent="true" Overwrite="true" />
</Target>

<Target Name="IgnoresAccessChecksToGenerator"
DependsOnTargets="GetIgnoresAccessChecksToGeneratorReferencePaths"
AfterTargets="AfterResolveReferences"
Inputs="@(_IACTG_InputReferencePath);$(_IACTG_ManifestFilePath)"
Outputs="@(_IACTG_OutputReferencePath);$(_IACTG_CodeFilePath)"
Returns="@(ReferencePath);@(Compile)">
<PublicizeInternals SourceReferences="@(ReferencePath)"
AssemblyNames="@(InternalsAssemblyName)"
ExcludeTypeNames="@(InternalsAssemblyExcludeTypeName)"
IntermediateOutputPath="$(_IACTG_IntermediatePath)"
GeneratedCodeFilePath="$(_IACTG_CodeFilePath)" />
<ItemGroup>
<ReferencePath Include="@(_IACTG_OutputReferencePath)" />
<ReferencePath Remove="@(_IACTG_OutputReferencePath->'%(OriginalItemSpec)')" />
<Compile Include="$(_IACTG_CodeFilePath)" />
</ItemGroup>
</Target>

<Target Name="IgnoresAccessChecksToGeneratorClean" AfterTargets="Clean">
<ItemGroup>
<_IACTG_Directory Include="$(_IACTG_IntermediatePath)" />
</ItemGroup>
<RemoveDir Directories="@(_IACTG_Directory)" />
</Target>

</Project>
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<InternalsAssemblyUseEmptyMethodBodies>false</InternalsAssemblyUseEmptyMethodBodies>
<Axxx>true</Axxx>
</PropertyGroup>

<ItemGroup>
<InternalsAssemblyName Include="Microsoft.CodeAnalysis" />
<InternalsAssemblyName Include="Microsoft.CodeAnalysis.CSharp" />
<InternalsAssemblyExcludeTypeName Include="Microsoft.CodeAnalysis.CSharp.AccessCheck" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="IgnoresAccessChecksToGenerator" Version="0.6.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.3.1" />
<PackageReference Include="IgnoresAccessChecksToGenerator" Version="0.7.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
</ItemGroup>

</Project>
6 changes: 6 additions & 0 deletions test/nuget.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="LocalFeed" value="../src/IgnoresAccessChecksToGenerator.Tasks/bin/Release/" />
</packageSources>
</configuration>

0 comments on commit 9d2bd05

Please sign in to comment.