Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] fix cases of missing @(Reference) (#7642
Browse files Browse the repository at this point in the history
)

Fixes: dotnet/maui#10154

Context? dotnet/maui#11364

If you have a solution setup with:

  * `ApplicationA.csproj` has a `@(ProjectReference)` to
    `LibraryB.csproj`.
  * `LibraryB.csproj` which has a `@(Reference)` to `LibraryC.dll`,
    built by-
  * `LibraryC.csproj`

The app will crash at runtime, due to a missing `LibraryC.dll`.

The workaround is for `LibraryB.csproj` to use `@(ProjectReference)`
to `LibraryC.csproj` instead of `@(Reference)` to `LibraryC.dll`.

However, it appears the same situation works in a .NET 7
self-contained console app:

	% dotnet publish --self-contained -r win-x64
	…
	% ls -1 .\bin\Debug\net7.0\win-x64\publish\LibraryC.dll
	LibraryC.dll

The underlying issue appears to be due to [`$(_FindDependencies)`][0]:

	<_FindDependencies Condition="'$(BuildingProject)' != 'true' and '$(_ResolveReferenceDependencies)' != 'true'">false</_FindDependencies>

In the console app, `$(BuildingProject)`=true and
`$(_FindDependencies)` is empty.

In the Android app, `$(BuildingProject)`=false and
`$(_FindDependencies)` is `false`.

It appears that the `BuildOnlySettings` target *should* be running in
Android apps when we do an "inner" build per `$(RuntimeIdentifier)`.
Simply updating `_ComputeFilesToPublishForRuntimeIdentifiers` so that
the `BuildOnlySettings` target is in `DependsOnTargets` fixes this.
However, this also causes satellite assemblies to now be automatically
found by the .NET SDK.  Update `@(_AndroidResolvedSatellitePaths)` so
that `@(ReferenceSatellitePaths)` is only included on Classic builds,
preventing duplicate entries.

[0]: https://github.com/dotnet/msbuild/blob/a2490dd3f78cce4abc8f9e6f1b5268437332818f/src/Tasks/Microsoft.Common.CurrentVersion.targets#L2322
  • Loading branch information
jonathanpeppers authored Jan 4, 2023
1 parent fe18cc6 commit 22f2001
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ _ResolveAssemblies MSBuild target.
</PropertyGroup>

<Target Name="_ComputeFilesToPublishForRuntimeIdentifiers"
DependsOnTargets="_FixupIntermediateAssembly;ResolveReferences;ComputeFilesToPublish;$(_RunAotMaybe)"
DependsOnTargets="BuildOnlySettings;_FixupIntermediateAssembly;ResolveReferences;ComputeFilesToPublish;$(_RunAotMaybe)"
Returns="@(ResolvedFileToPublish)">
<ItemGroup>
<ResolvedFileToPublish Remove="@(_SourceItemsToCopyToPublishDirectory)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,67 @@ public void DotNetIncremental ([Values (true, false)] bool isRelease, [Values ("
}
}

[Test]
public void ProjectDependencies ([Values(true, false)] bool projectReference)
{
// Setup dependencies App A -> Lib B -> Lib C
var path = Path.Combine ("temp", TestName);

var libB = new XASdkProject (outputType: "Library") {
ProjectName = "LibraryB",
IsRelease = true,
};
libB.Sources.Clear ();
libB.Sources.Add (new BuildItem.Source ("Foo.cs") {
TextContent = () => @"public class Foo {
public Foo () {
var bar = new Bar();
}
}",
});

var libC = new XASdkProject (outputType: "Library") {
ProjectName = "LibraryC",
IsRelease = true,
};
libC.Sources.Clear ();
libC.Sources.Add (new BuildItem.Source ("Bar.cs") {
TextContent = () => "public class Bar { }",
});

// Add a @(Reference) or @(ProjectReference)
if (projectReference) {
libB.AddReference (libC);
} else {
libB.OtherBuildItems.Add (new BuildItem.Reference ($@"..\{libC.ProjectName}\bin\Release\{libC.TargetFramework}\{libC.ProjectName}.dll"));
}

// Build libraries
var libCBuilder = CreateDotNetBuilder (libC, Path.Combine (path, libC.ProjectName));
Assert.IsTrue (libCBuilder.Build (), $"{libC.ProjectName} should succeed");
var libBBuilder = CreateDotNetBuilder (libB, Path.Combine (path, libB.ProjectName));
Assert.IsTrue (libBBuilder.Build (), $"{libB.ProjectName} should succeed");

var appA = new XASdkProject {
ProjectName = "AppA",
IsRelease = true,
Sources = {
new BuildItem.Source ("Bar.cs") {
TextContent = () => "public class Bar : Foo { }",
}
}
};
appA.AddReference (libB);
var appBuilder = CreateDotNetBuilder (appA, Path.Combine (path, appA.ProjectName));
Assert.IsTrue (appBuilder.Build (), $"{appA.ProjectName} should succeed");

var apkPath = Path.Combine (FullProjectDirectory, appA.OutputPath, $"{appA.PackageName}-Signed.apk");
FileAssert.Exists (apkPath);
var helper = new ArchiveAssemblyHelper (apkPath);
helper.AssertContainsEntry ($"assemblies/{libB.ProjectName}.dll");
helper.AssertContainsEntry ($"assemblies/{libC.ProjectName}.dll");
}

[Test]
public void SignAndroidPackage ()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1973,7 +1973,8 @@ because xbuild doesn't support framework reference assemblies.
DependsOnTargets="_ResolveAssemblies"
>
<ItemGroup>
<_AndroidResolvedSatellitePaths Include="@(ReferenceSatellitePaths)" />
<!-- In .NET 6+, the .NET SDK locates these files -->
<_AndroidResolvedSatellitePaths Condition=" '$(UsingAndroidNETSdk)' != 'true' " Include="@(ReferenceSatellitePaths)" />
<!-- Satellites from the current project, see: https://github.com/microsoft/msbuild/blob/master/src/Tasks/Microsoft.Common.CurrentVersion.targets#L4283-L4299 -->
<_AndroidResolvedSatellitePaths Include="@(IntermediateSatelliteAssembliesWithTargetPath->'$(OutDir)%(Culture)\$(TargetName).resources.dll')" />
</ItemGroup>
Expand Down

0 comments on commit 22f2001

Please sign in to comment.