Skip to content

Commit

Permalink
Move all of assembly store building code to a separate class
Browse files Browse the repository at this point in the history
This makes it possible to build assembly stores easily outside
`BuildApk`
  • Loading branch information
grendello committed Oct 9, 2024
1 parent e55c38f commit 1736671
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 69 deletions.
111 changes: 42 additions & 69 deletions src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -425,16 +425,12 @@ void AddAssemblies (ZipArchiveEx apk, bool debug, bool compress, IDictionary<And
string sourcePath;
AssemblyCompression.AssemblyData compressedAssembly = null;
string compressedOutputDir = Path.GetFullPath (Path.Combine (Path.GetDirectoryName (ApkOutputPath), "..", "lz4"));
AssemblyStoreGenerator? storeGenerator;
AssemblyStoreBuilder? storeBuilder = null;

if (UseAssemblyStore) {
storeGenerator = new AssemblyStoreGenerator (Log);
} else {
storeGenerator = null;
storeBuilder = new AssemblyStoreBuilder (Log);
}

AssemblyStoreAssemblyInfo? storeAssemblyInfo = null;

// Add user assemblies
AddAssembliesFromCollection (ResolvedUserAssemblies);

Expand All @@ -445,7 +441,7 @@ void AddAssemblies (ZipArchiveEx apk, bool debug, bool compress, IDictionary<And
return;
}

Dictionary<AndroidTargetArch, string> assemblyStorePaths = storeGenerator.Generate (AppSharedLibrariesDir);
Dictionary<AndroidTargetArch, string> assemblyStorePaths = storeBuilder.Generate (AppSharedLibrariesDir);

if (assemblyStorePaths.Count == 0) {
throw new InvalidOperationException ("Assembly store generator did not generate any stores");
Expand Down Expand Up @@ -498,53 +494,35 @@ void DoAddAssembliesFromArchCollection (AndroidTargetArch arch, Dictionary<strin
}

sourcePath = CompressAssembly (assembly);
if (UseAssemblyStore) {
storeBuilder.AddAssembly (sourcePath, assembly, includeDebugSymbols: debug);
continue;
}

// Add assembly
(string assemblyPath, string assemblyDirectory) = GetInArchiveAssemblyPath (assembly);
if (UseAssemblyStore) {
storeAssemblyInfo = new AssemblyStoreAssemblyInfo (sourcePath, assembly);
} else {
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (arch, sourcePath, Path.GetFileName (assemblyPath), this);
AddFileToArchiveIfNewer (apk, wrappedSourcePath, assemblyPath, compressionMethod: GetCompressionMethod (assemblyPath));
}
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (arch, sourcePath, Path.GetFileName (assemblyPath), this);
AddFileToArchiveIfNewer (apk, wrappedSourcePath, assemblyPath, compressionMethod: GetCompressionMethod (assemblyPath));

// Try to add config if exists
var config = Path.ChangeExtension (assembly.ItemSpec, "dll.config");
if (UseAssemblyStore) {
if (File.Exists (config)) {
storeAssemblyInfo.ConfigFile = new FileInfo (config);
}
} else {
AddAssemblyConfigEntry (apk, arch, assemblyDirectory, config);
}
AddAssemblyConfigEntry (apk, arch, assemblyDirectory, config);

// Try to add symbols if Debug
if (debug) {
var symbols = Path.ChangeExtension (assembly.ItemSpec, "pdb");
string? symbolsPath = null;

if (File.Exists (symbols)) {
symbolsPath = symbols;
}

if (!String.IsNullOrEmpty (symbolsPath)) {
if (UseAssemblyStore) {
storeAssemblyInfo.SymbolsFile = new FileInfo (symbolsPath);
} else {
string archiveSymbolsPath = assemblyDirectory + MonoAndroidHelper.MakeDiscreteAssembliesEntryName (Path.GetFileName (symbols));
string wrappedSymbolsPath = DSOWrapperGenerator.WrapIt (arch, symbolsPath, Path.GetFileName (archiveSymbolsPath), this);
AddFileToArchiveIfNewer (
apk,
wrappedSymbolsPath,
archiveSymbolsPath,
compressionMethod: GetCompressionMethod (archiveSymbolsPath)
);
}
}
if (!debug) {
continue;
}

if (UseAssemblyStore) {
storeGenerator.Add (storeAssemblyInfo);
string symbols = Path.ChangeExtension (assembly.ItemSpec, "pdb");
if (!File.Exists (symbols)) {
string archiveSymbolsPath = assemblyDirectory + MonoAndroidHelper.MakeDiscreteAssembliesEntryName (Path.GetFileName (symbols));
string wrappedSymbolsPath = DSOWrapperGenerator.WrapIt (arch, symbols, Path.GetFileName (archiveSymbolsPath), this);
AddFileToArchiveIfNewer (
apk,
wrappedSymbolsPath,
archiveSymbolsPath,
compressionMethod: GetCompressionMethod (archiveSymbolsPath)
);
}
}
}
Expand Down Expand Up @@ -655,33 +633,28 @@ void AddAssemblyConfigEntry (ZipArchiveEx apk, AndroidTargetArch arch, string as
}

string assemblyName = Path.GetFileName (assembly.ItemSpec);
if (UseAssemblyStore) {
// For discrete assembly entries we need to treat assemblies specially.
// All of the assemblies have their names mangled so that the possibility to clash with "real" shared
// library names is minimized. All of the assembly entries will start with a special character:
//
// `_` - for regular assemblies (e.g. `_Mono.Android.dll.so`)
// `-` - for satellite assemblies (e.g. `-es-Mono.Android.dll.so`)
//
// Second of all, we need to treat satellite assemblies with even more care.
// If we encounter one of them, we will return the culture as part of the path transformed
// so that it forms a `-culture-` assembly file name prefix, not a `culture/` subdirectory.
// This is necessary because Android doesn't allow subdirectories in `lib/{ABI}/`
//
string[] subdirParts = subDirectory.TrimEnd ('/').Split ('/');
if (subdirParts.Length == 1) {
// Not a satellite assembly
parts.Add (subDirectory);
parts.Add (assemblyName);
parts.Add (MonoAndroidHelper.MakeDiscreteAssembliesEntryName (assemblyName));
} else if (subdirParts.Length == 2) {
parts.Add (subdirParts[0]);
parts.Add (MonoAndroidHelper.MakeDiscreteAssembliesEntryName (assemblyName, subdirParts[1]));
} else {
// For discrete assembly entries we need to treat assemblies specially.
// All of the assemblies have their names mangled so that the possibility to clash with "real" shared
// library names is minimized. All of the assembly entries will start with a special character:
//
// `_` - for regular assemblies (e.g. `_Mono.Android.dll.so`)
// `-` - for satellite assemblies (e.g. `-es-Mono.Android.dll.so`)
//
// Second of all, we need to treat satellite assemblies with even more care.
// If we encounter one of them, we will return the culture as part of the path transformed
// so that it forms a `-culture-` assembly file name prefix, not a `culture/` subdirectory.
// This is necessary because Android doesn't allow subdirectories in `lib/{ABI}/`
//
string[] subdirParts = subDirectory.TrimEnd ('/').Split ('/');
if (subdirParts.Length == 1) {
// Not a satellite assembly
parts.Add (subDirectory);
parts.Add (MonoAndroidHelper.MakeDiscreteAssembliesEntryName (assemblyName));
} else if (subdirParts.Length == 2) {
parts.Add (subdirParts[0]);
parts.Add (MonoAndroidHelper.MakeDiscreteAssembliesEntryName (assemblyName, subdirParts[1]));
} else {
throw new InvalidOperationException ($"Internal error: '{assembly}' `DestinationSubDirectory` metadata has too many components ({parts.Count} instead of 1 or 2)");
}
throw new InvalidOperationException ($"Internal error: '{assembly}' `DestinationSubDirectory` metadata has too many components ({parts.Count} instead of 1 or 2)");
}

string assemblyFilePath = MonoAndroidHelper.MakeZipArchivePath (ArchiveAssembliesPath, parts);
Expand Down
45 changes: 45 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Utilities/AssemblyStoreBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.IO;

using Microsoft.Android.Build.Tasks;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
using Xamarin.Android.Tools;

namespace Xamarin.Android.Tasks;

class AssemblyStoreBuilder
{
readonly TaskLoggingHelper log;
readonly AssemblyStoreGenerator storeGenerator;

public AssemblyStoreBuilder (TaskLoggingHelper log)
{
this.log = log;
storeGenerator = new (log);
}

public void AddAssembly (string assemblySourcePath, ITaskItem assemblyItem, bool includeDebugSymbols)
{
var storeAssemblyInfo = new AssemblyStoreAssemblyInfo (assemblySourcePath, assemblyItem);

// Try to add config if exists. We use assemblyItem, because `sourcePath` might refer to a compressed
// assembly file in a different location.
var config = Path.ChangeExtension (assemblyItem.ItemSpec, "dll.config");
if (File.Exists (config)) {
storeAssemblyInfo.ConfigFile = new FileInfo (config);
}

if (includeDebugSymbols) {
string debugSymbolsPath = Path.ChangeExtension (assemblyItem.ItemSpec, "pdb");
if (File.Exists (debugSymbolsPath)) {
storeAssemblyInfo.SymbolsFile = new FileInfo (debugSymbolsPath);
}
}

storeGenerator.Add (storeAssemblyInfo);
}

public Dictionary<AndroidTargetArch, string> Generate (string outputDirectoryPath) => storeGenerator.Generate (outputDirectoryPath);
}

0 comments on commit 1736671

Please sign in to comment.