Skip to content

Commit

Permalink
[One .NET] conditionally add generated\*\*.cs to @(Compile) (#6291)
Browse files Browse the repository at this point in the history
Fixes: #6280

.NET 6 projects have the following issue:

 1. Build a .NET 6 project with a `.jar` to create a C# binding.
 2. Delete the `.jar` completely & build again.
 3. The generated C# binding types remain in the assembly!

We have the following expression to decide when C#-binding related
targets should be completely skipped:

	Condition=" '$(UsingAndroidNETSdk)' != 'true' Or '@(InputJar->Count())' != '0' Or '@(EmbeddedJar->Count())' != '0' Or '@(LibraryProjectZip->Count())' != '0' "

This allows the targets to run for "legacy" Xamarin.Android binding
projects, and .NET 6 project when certain item groups are non-empty.

We were missing this condition on the `AddBindingsToCompile` MSBuild
target!

	<Target Name="AddBindingsToCompile" DependsOnTargets="GenerateBindings">
	  <ItemGroup>
	    <Compile Include="$(IntermediateOutputPath)generated\*\*.cs" />
	  </ItemGroup>
	</Target>

I don't think we necessarily have to delete this directory; these
files should just not be added to the `@(Compile)` item group.

Instead of copying this long `Condition` to a third place, refactor
the expression into a new `_SetAndroidGenerateManagedBindings`
MSBuild target.  All three places can use a simpler expression that
will be harder to mess up:

	Condition=" '$(_AndroidGenerateManagedBindings)' == 'true' "

I updated a test to verify removing a `.jar` removes the C# classes
from the compiled assembly.
  • Loading branch information
jonathanpeppers committed Sep 14, 2021
1 parent bf77a7c commit 33e92ca
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 6 deletions.
Expand Up @@ -28,16 +28,24 @@ It is shared between "legacy" binding projects and .NET 5 projects.
<NoWarn Condition=" '$(DocumentationFile)' != '' ">$(NoWarn);CS1573;CS1591</NoWarn>
</PropertyGroup>

<Target Name="ExportJarToXml"
DependsOnTargets="$(ExportJarToXmlDependsOnTargets)"
<Target Name="_SetAndroidGenerateManagedBindings"
Condition=" '$(UsingAndroidNETSdk)' != 'true' Or '@(InputJar->Count())' != '0' Or '@(EmbeddedJar->Count())' != '0' Or '@(LibraryProjectZip->Count())' != '0' ">
<PropertyGroup>
<!-- Used throughout to determine if C# binding-related targets should skip -->
<_AndroidGenerateManagedBindings>true</_AndroidGenerateManagedBindings>
</PropertyGroup>
</Target>

<Target Name="ExportJarToXml"
Condition=" '$(_AndroidGenerateManagedBindings)' == 'true' "
DependsOnTargets="$(ExportJarToXmlDependsOnTargets)">
<PropertyGroup>
<AllowUnsafeBlocks Condition=" '$(AllowUnsafeBlocks)' != 'true' ">true</AllowUnsafeBlocks>
</PropertyGroup>
</Target>

<Target Name="GenerateBindings"
Condition=" '$(UsingAndroidNETSdk)' != 'true' Or '@(InputJar->Count())' != '0' Or '@(EmbeddedJar->Count())' != '0' Or '@(LibraryProjectZip->Count())' != '0' "
Condition=" '$(_AndroidGenerateManagedBindings)' == 'true' "
DependsOnTargets="ExportJarToXml;_ResolveMonoAndroidSdks"
Inputs="$(ApiOutputFile);@(TransformFile);@(ReferencePath);@(ReferenceDependencyPaths);@(_AndroidMSBuildAllProjects)"
Outputs="$(_GeneratorStampFile)">
Expand Down Expand Up @@ -79,7 +87,9 @@ It is shared between "legacy" binding projects and .NET 5 projects.

</Target>

<Target Name="AddBindingsToCompile" DependsOnTargets="GenerateBindings">
<Target Name="AddBindingsToCompile"
Condition=" '$(_AndroidGenerateManagedBindings)' == 'true' "
DependsOnTargets="GenerateBindings">
<!-- Add the files to list of things to be compiled -->
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)generated\*\*.cs" />
Expand Down
Expand Up @@ -112,6 +112,7 @@ projects, these properties are set in Xamarin.Android.Legacy.targets.
$(CoreResolveReferencesDependsOn);
UpdateAndroidInterfaceProxies;
UpdateAndroidResources;
_SetAndroidGenerateManagedBindings;
AddBindingsToCompile;
</ResolveReferencesDependsOn>
<_UpdateAndroidResourcesDependsOn>
Expand Down
Expand Up @@ -300,14 +300,24 @@ public void AppWithSingleJar ()
};

var dotnet = CreateDotNetBuilder (proj);
Assert.IsTrue (dotnet.Build (), "build should succeed");
Assert.IsTrue (dotnet.Build (), "first build should succeed");

var assemblyPath = Path.Combine (FullProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.dll");
var typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceJarTest";
FileAssert.Exists (assemblyPath);
using (var assembly = AssemblyDefinition.ReadAssembly (assemblyPath)) {
var typeName = "Com.Xamarin.Android.Test.Msbuildtest.JavaSourceJarTest";
Assert.IsNotNull (assembly.MainModule.GetType (typeName), $"{assemblyPath} should contain {typeName}");
}

// Remove the @(AndroidLibrary) & build again
proj.Sources.RemoveAt (proj.Sources.Count - 1);
Directory.Delete (Path.Combine (FullProjectDirectory, "Jars"), recursive: true);
Assert.IsTrue (dotnet.Build (), "second build should succeed");

FileAssert.Exists (assemblyPath);
using (var assembly = AssemblyDefinition.ReadAssembly (assemblyPath)) {
Assert.IsNull (assembly.MainModule.GetType (typeName), $"{assemblyPath} should *not* contain {typeName}");
}
}

[Test]
Expand Down
Expand Up @@ -187,6 +187,7 @@ projects. .NET 5 projects will not import this file.

<ResolveReferencesDependsOn>
$(ResolveReferencesDependsOn);
_SetAndroidGenerateManagedBindings;
AddBindingsToCompile;
AddEmbeddedJarsAsResources;
AddEmbeddedReferenceJarsAsResources;
Expand Down

0 comments on commit 33e92ca

Please sign in to comment.