Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] fix Inputs for _Generate*Java* targ…
Browse files Browse the repository at this point in the history
…ets (dotnet#9174)

Fixes: dotnet#8967
Context: dotnet#9001

You can cause a build error in .NET 8 by doing:

* Start an x86 or x86_64 emulator
* `dotnet build -t:Run`
* Close the emulator, attach an arm or arm64 device
* `dotnet build -t:Run`

Emits the error:

    Xamarin.Android.Common.targets(2063,3): error XA3006: Could not compile native assembly file: typemaps.x86_64.ll
    stderr | C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\34.0.113\tools\binutils\bin\llc.exe: error: C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\34.0.113\tools\binutils\bin\llc.exe: typemaps.x86_64.ll: error: Could not open input file: no such file or directory

This works fine in Visual Studio, but not at the command-line.

The underlying problem is due to `_GeneratePackageManagerJava` target
running, while the `_GenerateJavaStubs` target *did not*:

    Skipping target "_GenerateJavaStubs" because all output files are up-to-date with respect to the input files.
    ...
    Input file "obj\Debug\net8.0-android\resolvedassemblies.hash" is newer than output file "obj\Debug\net8.0-android\stamp\_GeneratePackageManagerJava.stamp".

These two targets should almost always run together, so we should
ensure that they do.

This problem also doesn't happen .NET 9, as both targets are
invalidated for a different reason:

    Target Name=_LinkAssembliesNoShrink Project=UnnamedProject.csproj
    Building target "_LinkAssembliesNoShrink" completely.
    Output file "obj\Debug\android\assets\x86_64\UnnamedProject.dll" does not exist.

Since, we build per-RID in .NET 9, `obj\Debug\android\assets\x86_64\UnnamedProject.dll`
has an `x86_64` in the path, which is not present in the .NET 8 build.

Reviewing the two sets of `Inputs`:

    <Target Name="_GenerateJavaStubs"
        ...
        Inputs="@(_AndroidMSBuildAllProjects);@(_ResolvedUserMonoAndroidAssemblies);$(_AndroidManifestAbs);$(_AndroidBuildPropertiesCache);@(AndroidEnvironment);@(LibraryEnvironments)"
    ...
    <Target Name="_GeneratePackageManagerJava"
        ...
        Inputs="@(_AndroidMSBuildAllProjects);$(_ResolvedUserAssembliesHashFile);$(MSBuildProjectFile);$(_AndroidBuildPropertiesCache);@(AndroidEnvironment);@(LibraryEnvironments)"

Let's align them more closely by:

* Track assembly changes in the exact same way:

    $(_ResolvedUserAssembliesHashFile);@(_ResolvedUserMonoAndroidAssemblies);

This way if an assembly is added, removed, or timestamp changed: both
targets are in sync.

* Don't track `$(MSBuildProjectFile)`, this should already be in
  `@(_AndroidMSBuildAllProjects)`.

With this change in place manually, I'm not able to reproduce the
problem any longer.

PR dotnet#9001 may also have fixed this issue, but it could cause targets to
run on every incremental build -- a performance issue.
  • Loading branch information
jonathanpeppers authored Aug 6, 2024
1 parent 7451f5b commit 175f3a0
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1655,5 +1655,36 @@ public void SimilarAndroidXAssemblyNames ([Values(true, false)] bool publishTrim
using var builder = CreateApkBuilder ();
Assert.IsTrue (builder.Build (proj), "Build should have succeeded.");
}

[Test]
public void IncrementalBuildDifferentDevice()
{
var proj = new XamarinAndroidApplicationProject {
Imports = {
new Import (() => "MockPrimaryCpuAbi.targets") {
TextContent = () =>
"""
<Project>
<!-- This target "mocks" what _GetPrimaryCpuAbi does -->
<Target Name="_MockPrimaryCpuAbi" BeforeTargets="_CreatePropertiesCache">
<PropertyGroup>
<RuntimeIdentifier>$(_SingleRID)</RuntimeIdentifier>
<RuntimeIdentifiers></RuntimeIdentifiers>
<AndroidSupportedAbis>$(_SingleABI)</AndroidSupportedAbis>
</PropertyGroup>
</Target>
</Project>
"""
},
},
};
using var builder = CreateApkBuilder ();
builder.Target = "Build";
builder.BuildingInsideVisualStudio = false;
Assert.IsTrue (builder.Build (proj, parameters: [ "_SingleRID=android-arm64", "_SingleABI=arm64-v8a" ]),
"first build should have succeeded.");
Assert.IsTrue (builder.Build (proj, parameters: [ "_SingleRID=android-x64", "_SingleABI=x86_64" ], doNotCleanupOnUpdate: true),
"second build should have succeeded.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1444,7 +1444,7 @@ because xbuild doesn't support framework reference assemblies.

<Target Name="_GenerateJavaStubs"
DependsOnTargets="$(_GenerateJavaStubsDependsOnTargets);$(BeforeGenerateAndroidManifest)"
Inputs="@(_AndroidMSBuildAllProjects);@(_ResolvedUserMonoAndroidAssemblies);$(_AndroidManifestAbs);$(_AndroidBuildPropertiesCache);@(AndroidEnvironment);@(LibraryEnvironments)"
Inputs="@(_AndroidMSBuildAllProjects);$(_ResolvedUserAssembliesHashFile);@(_ResolvedUserMonoAndroidAssemblies);$(_AndroidManifestAbs);$(_AndroidBuildPropertiesCache);@(AndroidEnvironment);@(LibraryEnvironments)"
Outputs="$(_AndroidStampDirectory)_GenerateJavaStubs.stamp">

<PropertyGroup>
Expand Down Expand Up @@ -1691,7 +1691,7 @@ because xbuild doesn't support framework reference assemblies.

<Target Name="_GeneratePackageManagerJava"
DependsOnTargets="$(_GeneratePackageManagerJavaDependsOn)"
Inputs="@(_AndroidMSBuildAllProjects);$(_ResolvedUserAssembliesHashFile);$(MSBuildProjectFile);$(_AndroidBuildPropertiesCache);@(AndroidEnvironment);@(LibraryEnvironments)"
Inputs="@(_AndroidMSBuildAllProjects);$(_ResolvedUserAssembliesHashFile);@(_ResolvedUserMonoAndroidAssemblies);$(_AndroidBuildPropertiesCache);@(AndroidEnvironment);@(LibraryEnvironments)"
Outputs="$(_AndroidStampDirectory)_GeneratePackageManagerJava.stamp">
<!-- Create java needed for Mono runtime -->
<GeneratePackageManagerJava
Expand Down

0 comments on commit 175f3a0

Please sign in to comment.