Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] use ProjectSpecificTaskObjectKey in `…
Browse files Browse the repository at this point in the history
…<PrepareDSOWrapperState/>` (#9340)

Context: dotnet/maui#24539 (comment)

In .NET MAUI's build, they failed to bump .NET for Android because of
the following error:

    dotnet\packs\Microsoft.Android.Sdk.Windows\35.0.0-rc.2.130\tools\Xamarin.Android.Common.Debugging.targets(139,2): error XABLD7009: System.InvalidOperationException: Internal error: archive DSO stub location not known for architecture 'X86'
    at Xamarin.Android.Tasks.DSOWrapperGenerator.WrapIt(AndroidTargetArch targetArch, String payloadFilePath, String outputFileName, IBuildEngine4 buildEngine, TaskLoggingHelper log) in /Users/runner/work/1/s/xamarin-android/src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs:line 86
    at Xamarin.Android.Tasks.BuildApk.AddRuntimeConfigBlob(ZipArchiveEx apk) in /Users/runner/work/1/s/xamarin-android/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs:line 404
    at Xamarin.Android.Tasks.BuildApk.ExecuteWithAbi(String[] supportedAbis, String apkInputPath, String apkOutputPath, Boolean debug, Boolean compress, IDictionary`2 compressedAssembliesInfo, String assemblyStoreApkName) in /Users/runner/work/1/s/xamarin-android/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs:line 215
    at Xamarin.Android.Tasks.BuildApk.RunTask() in /Users/runner/work/1/s/xamarin-android/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs:line 357
    at Microsoft.Android.Build.Tasks.AndroidTask.Execute() in /Users/runner/work/1/s/xamarin-android/external/xamarin-android-tools/src/Microsoft.Android.Build.BaseTasks/AndroidTask.cs:line 25

In 5ebcb1d, we introduced some MSBuild `RegisterTaskObject()` usage
that failed in specific way:

* MAUI has a `.sln` with multiple "app" projects: device tests,
  samples, etc. building in parallel

* The `<PrepareDSOWrapperState/>` MSBuild task runs for project A,
  saving x64 and arm64 values.

* Project B goes to run `<BuildApk/>` but x86 is missing.

For now, we can fix this by using `ProjectSpecificTaskObjectKey()` that
wraps the key with a `Tuple` such as:

    (key, WorkingDirectory)

Which, should result in a unique key per project.

In a future PR, we could consider removing this `RegisterTaskObject()`
usage completely, and doing all the work inside the `<BuildApk/>`
MSBuild task instead.
  • Loading branch information
jonathanpeppers committed Sep 30, 2024
1 parent dc00a0c commit 65a4c8b
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 21 deletions.
21 changes: 15 additions & 6 deletions src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,11 +371,20 @@ public override bool RunTask ()
OutputFiles = outputFiles.Select (a => new TaskItem (a)).ToArray ();

Log.LogDebugTaskItems (" [Output] OutputFiles :", OutputFiles);
DSOWrapperGenerator.CleanUp (BuildEngine4, Log);
DSOWrapperGenerator.CleanUp (this);

return !Log.HasLoggedErrors;
}

internal DSOWrapperGenerator.Config EnsureConfig ()
{
var config = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal<DSOWrapperGenerator.Config> (ProjectSpecificTaskObjectKey (DSOWrapperGenerator.RegisteredConfigKey), RegisteredTaskObjectLifetime.Build);
if (config is null) {
throw new InvalidOperationException ("Internal error: no registered config found");
}
return config;
}

static Regex FileGlobToRegEx (string fileGlob, RegexOptions options)
{
StringBuilder sb = new StringBuilder ();
Expand Down Expand Up @@ -405,7 +414,7 @@ void AddRuntimeConfigBlob (ZipArchiveEx apk)
// Prefix it with `a` because bundletool sorts entries alphabetically, and this will place it right next to `assemblies.*.blob.so`, which is what we
// like since we can finish scanning the zip central directory earlier at startup.
string inArchivePath = MakeArchiveLibPath (abi, "libarc.bin.so");
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (MonoAndroidHelper.AbiToTargetArch (abi), RuntimeConfigBinFilePath, Path.GetFileName (inArchivePath), BuildEngine4, Log);
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (MonoAndroidHelper.AbiToTargetArch (abi), RuntimeConfigBinFilePath, Path.GetFileName (inArchivePath), this);
AddFileToArchiveIfNewer (apk, wrappedSourcePath, inArchivePath, compressionMethod: GetCompressionMethod (inArchivePath));
}
}
Expand Down Expand Up @@ -450,7 +459,7 @@ void AddAssemblies (ZipArchiveEx apk, bool debug, bool compress, IDictionary<And
foreach (var kvp in assemblyStorePaths) {
string abi = MonoAndroidHelper.ArchToAbi (kvp.Key);
inArchivePath = MakeArchiveLibPath (abi, "lib" + Path.GetFileName (kvp.Value));
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (kvp.Key, kvp.Value, Path.GetFileName (inArchivePath), BuildEngine4, Log);
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (kvp.Key, kvp.Value, Path.GetFileName (inArchivePath), this);
AddFileToArchiveIfNewer (apk, wrappedSourcePath, inArchivePath, GetCompressionMethod (inArchivePath));
}

Expand Down Expand Up @@ -495,7 +504,7 @@ void DoAddAssembliesFromArchCollection (AndroidTargetArch arch, Dictionary<strin
if (UseAssemblyStore) {
storeAssemblyInfo = new AssemblyStoreAssemblyInfo (sourcePath, assembly);
} else {
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (arch, sourcePath, Path.GetFileName (assemblyPath), BuildEngine4, Log);
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (arch, sourcePath, Path.GetFileName (assemblyPath), this);
AddFileToArchiveIfNewer (apk, wrappedSourcePath, assemblyPath, compressionMethod: GetCompressionMethod (assemblyPath));
}

Expand Down Expand Up @@ -523,7 +532,7 @@ void DoAddAssembliesFromArchCollection (AndroidTargetArch arch, Dictionary<strin
storeAssemblyInfo.SymbolsFile = new FileInfo (symbolsPath);
} else {
string archiveSymbolsPath = assemblyDirectory + MonoAndroidHelper.MakeDiscreteAssembliesEntryName (Path.GetFileName (symbols));
string wrappedSymbolsPath = DSOWrapperGenerator.WrapIt (arch, symbolsPath, Path.GetFileName (archiveSymbolsPath), BuildEngine4, Log);
string wrappedSymbolsPath = DSOWrapperGenerator.WrapIt (arch, symbolsPath, Path.GetFileName (archiveSymbolsPath), this);
AddFileToArchiveIfNewer (
apk,
wrappedSymbolsPath,
Expand Down Expand Up @@ -628,7 +637,7 @@ void AddAssemblyConfigEntry (ZipArchiveEx apk, AndroidTargetArch arch, string as
}

Log.LogDebugMessage ($"Adding {configFile} as the archive file is out of date.");
string wrappedConfigFile = DSOWrapperGenerator.WrapIt (arch, configFile, Path.GetFileName (inArchivePath), BuildEngine4, Log);
string wrappedConfigFile = DSOWrapperGenerator.WrapIt (arch, configFile, Path.GetFileName (inArchivePath), this);
apk.AddFileAndFlush (wrappedConfigFile, inArchivePath, compressionMethod);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public override bool RunTask ()
}

var config = new DSOWrapperGenerator.Config (stubPaths, AndroidBinUtilsDirectory, BaseOutputDirectory);
BuildEngine4.RegisterTaskObjectAssemblyLocal (DSOWrapperGenerator.RegisteredConfigKey, config, RegisteredTaskObjectLifetime.Build);
BuildEngine4.RegisterTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (DSOWrapperGenerator.RegisteredConfigKey), config, RegisteredTaskObjectLifetime.Build);

return !Log.HasLoggedErrors;
}
Expand Down
19 changes: 5 additions & 14 deletions src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,6 @@ public Config (Dictionary<AndroidTargetArch, ITaskItem> stubPaths, string androi
//
const ulong PayloadSectionAlignment = 0x4000;

static Config EnsureConfig (IBuildEngine4 buildEngine)
{
var config = buildEngine.GetRegisteredTaskObjectAssemblyLocal<Config> (RegisteredConfigKey, RegisteredTaskObjectLifetime.Build);
if (config == null) {
throw new InvalidOperationException ("Internal error: no registered config found");
}

return config;
}

static string GetArchOutputPath (AndroidTargetArch targetArch, Config config)
{
return Path.Combine (config.BaseOutputDirectory, MonoAndroidHelper.ArchToRid (targetArch), "wrapped");
Expand All @@ -72,10 +62,11 @@ static string GetArchOutputPath (AndroidTargetArch targetArch, Config config)
/// Puts the indicated file (<paramref name="payloadFilePath"/>) inside an ELF shared library and returns
/// path to the wrapped file.
/// </summary>
public static string WrapIt (AndroidTargetArch targetArch, string payloadFilePath, string outputFileName, IBuildEngine4 buildEngine, TaskLoggingHelper log)
public static string WrapIt (AndroidTargetArch targetArch, string payloadFilePath, string outputFileName, BuildApk task)
{
TaskLoggingHelper log = task.Log;
log.LogDebugMessage ($"[{targetArch}] Putting '{payloadFilePath}' inside ELF shared library '{outputFileName}'");
Config config = EnsureConfig (buildEngine);
Config config = task.EnsureConfig ();
string outputDir = GetArchOutputPath (targetArch, config);
Directory.CreateDirectory (outputDir);

Expand Down Expand Up @@ -116,9 +107,9 @@ public static string WrapIt (AndroidTargetArch targetArch, string payloadFilePat
/// created by this class. The reason to do so is to ensure that we don't package any "stale" content and those
/// wrapper files aren't part of any dependency chain so it's hard to check their up to date state.
/// </summary>
public static void CleanUp (IBuildEngine4 buildEngine, TaskLoggingHelper log)
public static void CleanUp (BuildApk task)
{
Config config = EnsureConfig (buildEngine);
Config config = task.EnsureConfig();

foreach (var kvp in config.DSOStubPaths) {
string outputDir = GetArchOutputPath (kvp.Key, config);
Expand Down

0 comments on commit 65a4c8b

Please sign in to comment.