Skip to content

Commit bfe4c6f

Browse files
committed
The basics
1 parent b1cb05e commit bfe4c6f

File tree

8 files changed

+257
-64
lines changed

8 files changed

+257
-64
lines changed

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ properties that determine build ordering.
6767
_GenerateEnvironmentFiles;
6868
_CompileJava;
6969
_CreateApplicationSharedLibraries;
70+
_LinkNativeRuntime;
7071
_CompileDex;
7172
$(_AfterCompileDex);
7273
_CreateBaseApk;

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeRuntime.targets

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,39 @@ Contains code to build and link the native runtime at application build time.
77
***********************************************************************************************
88
-->
99
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
10+
<UsingTask TaskName="Xamarin.Android.Tasks.GetNativeRuntimeComponents" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
1011
<UsingTask TaskName="Xamarin.Android.Tasks.LinkNativeRuntime" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
1112

12-
<PropertyGroup>
13-
<_EnableNativeRuntimeLinking
14-
</PropertyGroup>
13+
<Target Name="_PrepareUnifiedNativeRuntimeItems">
14+
<ItemGroup>
15+
<_UnifiedNativeRuntime Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libmonodroid-unified.so">
16+
<abi>%(_BuildTargetAbis.Identity)</abi>
17+
</_UnifiedNativeRuntime>
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<_ResolvedNativeArchive Include="@(ResolvedFileToPublish)" Condition=" '%(ResolvedFileToPublish.Extension)' == '.a' " />
22+
</ItemGroup>
23+
24+
<GetNativeRuntimeComponents
25+
MonoComponents="@(_MonoComponent)"
26+
ResolvedNativeArchives="@(_ResolvedNativeArchive)">
27+
<Output TaskParameter="NativeArchives" ItemName="_SelectedNativeArchive" />
28+
</GetNativeRuntimeComponents>
29+
</Target>
1530

1631
<Target Name="_LinkNativeRuntime"
17-
DependsOnTargets="_PrepareMonoComponentItems"
32+
DependsOnTargets="_PrepareMonoComponentItems;_CompileNativeAssemblySources;_PrepareUnifiedNativeRuntimeItems"
33+
Inputs="@(_NativeAssemblyTarget);@(_SelectedNativeArchive)"
34+
Outputs="@(_UnifiedNativeRuntime)"
1835
Condition=" '$(_AndroidEnableNativeRuntimeLinking)' == 'true' ">
1936
<LinkNativeRuntime
2037
MonoComponents="@(_MonoComponent)"
2138
AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)"
39+
NativeArchives="@(_SelectedNativeArchive)"
40+
NativeObjectFiles="@(_NativeAssemblyTarget)"
41+
OutputRuntimes="@(_UnifiedNativeRuntime)"
42+
SupportedAbis="@(_BuildTargetAbis)"
2243
/>
2344
</Target>
2445
</Project>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System;
2+
using System.IO;
3+
using System.Collections.Generic;
4+
5+
using Microsoft.Build.Framework;
6+
using Microsoft.Build.Utilities;
7+
using Microsoft.Android.Build.Tasks;
8+
9+
namespace Xamarin.Android.Tasks;
10+
11+
public class GetNativeRuntimeComponents : AndroidTask
12+
{
13+
public override string TaskPrefix => "GNRC";
14+
15+
public ITaskItem[] MonoComponents { get; set; }
16+
17+
[Required]
18+
public ITaskItem[] ResolvedNativeArchives { get; set; }
19+
20+
[Output]
21+
public ITaskItem[] NativeArchives { get; set; }
22+
23+
public override bool RunTask ()
24+
{
25+
var components = new NativeRuntimeComponents (MonoComponents);
26+
var archives = new List<ITaskItem> ();
27+
foreach (NativeRuntimeComponents.Archive archiveItem in components.KnownArchives) {
28+
if (!archiveItem.Include) {
29+
continue;
30+
}
31+
MakeItems (archiveItem, archives);
32+
}
33+
34+
NativeArchives = archives.ToArray ();
35+
return !Log.HasLoggedErrors;
36+
}
37+
38+
void MakeItems (NativeRuntimeComponents.Archive archive, List<ITaskItem> archives)
39+
{
40+
foreach (ITaskItem resolvedArchive in ResolvedNativeArchives) {
41+
string fileName = Path.GetFileName (resolvedArchive.ItemSpec);
42+
if (String.Compare (fileName, archive.Name, StringComparison.OrdinalIgnoreCase) == 0) {
43+
archives.Add (DoMakeItem (resolvedArchive));
44+
}
45+
}
46+
47+
ITaskItem DoMakeItem (ITaskItem resolved)
48+
{
49+
var ret = new TaskItem (resolved.ItemSpec);
50+
string abi = MonoAndroidHelper.RidToAbi (resolved.GetRequiredMetadata ("_ResolvedNativeArchive", "RuntimeIdentifier", Log));
51+
ret.SetMetadata ("Abi", abi);
52+
53+
return ret;
54+
}
55+
}
56+
}

src/Xamarin.Android.Build.Tasks/Tasks/LinkNativeRuntime.cs

Lines changed: 38 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -16,88 +16,68 @@ namespace Xamarin.Android.Tasks;
1616

1717
public class LinkNativeRuntime : AndroidAsyncTask
1818
{
19-
class Archive
20-
{
21-
public readonly string Name;
22-
public readonly Func<Archive, bool> Include = (Archive) => true;
23-
24-
public Archive (string name, Func<Archive, bool>? include = null)
25-
{
26-
Name = name;
27-
if (include != null) {
28-
Include = include;
29-
}
30-
}
31-
}
19+
public override string TaskPrefix => "LNR";
3220

33-
class MonoComponentArchive : Archive
34-
{
35-
public readonly string ComponentName;
21+
public ITaskItem[] MonoComponents { get; set; }
3622

37-
public MonoComponentArchive (string name, string componentName, Func<Archive, bool> include)
38-
: base (name, include)
39-
{
40-
ComponentName = componentName;
41-
}
42-
}
23+
[Required]
24+
public string AndroidBinUtilsDirectory { get; set; }
4325

44-
readonly List<Archive> KnownArchives;
26+
[Required]
27+
public ITaskItem[] NativeArchives { get; set; }
4528

46-
public override string TaskPrefix => "LNR";
29+
[Required]
30+
public ITaskItem[] NativeObjectFiles { get; set; }
4731

48-
public ITaskItem[] MonoComponents { get; set; }
32+
[Required]
33+
public ITaskItem[] OutputRuntimes { get; set; }
4934

5035
[Required]
51-
public string AndroidBinUtilsDirectory { get; set; }
36+
public ITaskItem[] SupportedAbis { get; set; }
5237

53-
public LinkNativeRuntime ()
38+
public override System.Threading.Tasks.Task RunTaskAsync ()
5439
{
55-
KnownArchives = new () {
56-
new MonoComponentArchive ("libmono-component-diagnostics_tracing-static.a", "diagnostics_tracing", MonoComponentPresent),
57-
new MonoComponentArchive ("libmono-component-diagnostics_tracing-stub-static.a", "diagnostics_tracing", MonoComponentAbsent),
58-
new MonoComponentArchive ("libmono-component-marshal-ilgen-static.a", "marshal-ilgen", MonoComponentPresent),
59-
new MonoComponentArchive ("libmono-component-marshal-ilgen-stub-static.a", "marshal-ilgen", MonoComponentAbsent),
60-
61-
new Archive ("libmonosgen-2.0.a"),
62-
new Archive ("libSystem.Globalization.Native.a"),
63-
new Archive ("libSystem.IO.Compression.Native.a"),
64-
new Archive ("libSystem.Native.a"),
65-
new Archive ("libSystem.Security.Cryptography.Native.Android.a"),
66-
};
40+
return this.WhenAll (SupportedAbis, LinkRuntime);
6741
}
6842

69-
public override System.Threading.Tasks.Task RunTaskAsync ()
43+
void LinkRuntime (ITaskItem abiItem)
7044
{
71-
throw new NotImplementedException ();
45+
string abi = abiItem.ItemSpec;
46+
Log.LogDebugMessage ($"LinkRuntime ({abi})");
47+
var linker = new NativeLinker (Log, abi);
48+
linker.Link (
49+
GetFirstAbiItem (OutputRuntimes, "_UnifiedNativeRuntime", abi),
50+
GetAbiItems (NativeObjectFiles, "_NativeAssemblyTarget", abi),
51+
GetAbiItems (NativeArchives, "_SelectedNativeArchive", abi)
52+
);
7253
}
7354

74-
bool MonoComponentExists (Archive archive)
55+
List<ITaskItem> GetAbiItems (ITaskItem[] source, string itemName, string abi)
7556
{
76-
if (MonoComponents == null || MonoComponents.Length == 0) {
77-
return false;
78-
}
79-
80-
var mcArchive = archive as MonoComponentArchive;
81-
if (mcArchive == null) {
82-
throw new ArgumentException (nameof (archive), "Must be an instance of MonoComponentArchive");
83-
}
57+
var ret = new List<ITaskItem> ();
8458

85-
foreach (ITaskItem item in MonoComponents) {
86-
if (String.Compare (item.ItemSpec, mcArchive.ComponentName, StringComparison.OrdinalIgnoreCase) == 0) {
87-
return true;
59+
foreach (ITaskItem item in source) {
60+
if (AbiMatches (abi, item, itemName)) {
61+
ret.Add (item);
8862
}
8963
}
9064

91-
return false;
65+
return ret;
9266
}
9367

94-
bool MonoComponentAbsent (Archive archive)
68+
ITaskItem GetFirstAbiItem (ITaskItem[] source, string itemName, string abi)
9569
{
96-
return !MonoComponentExists (archive);
70+
foreach (ITaskItem item in source) {
71+
if (AbiMatches (abi, item, itemName)) {
72+
return item;
73+
}
74+
}
75+
76+
throw new InvalidOperationException ($"Internal error: item '{itemName}' for ABI '{abi}' not found");
9777
}
9878

99-
bool MonoComponentPresent (Archive archive)
79+
bool AbiMatches (string abi, ITaskItem item, string itemName)
10080
{
101-
return MonoComponentExists (archive);
81+
return String.Compare (abi, item.GetRequiredMetadata (itemName, "Abi", Log), StringComparison.OrdinalIgnoreCase) == 0;
10282
}
10383
}

src/Xamarin.Android.Build.Tasks/Utilities/AssemblyStoreGenerator.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,11 @@ string Generate (string baseOutputDirectory, AndroidTargetArch arch, List<Assemb
100100
};
101101

102102
string androidAbi = MonoAndroidHelper.ArchToAbi (arch);
103+
string outputDir = Path.Combine (baseOutputDirectory, androidAbi);
104+
Directory.CreateDirectory (outputDir);
105+
103106
uint infoCount = (uint)infos.Count;
104-
string storePath = Path.Combine (baseOutputDirectory, androidAbi, $"assemblies.{androidAbi}.blob.so");
107+
string storePath = Path.Combine (outputDir, $"assemblies.{androidAbi}.blob.so");
105108
var index = new List<AssemblyStoreIndexEntry> ();
106109
var descriptors = new List<AssemblyStoreEntryDescriptor> ();
107110
ulong namesSize = 0;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
using Microsoft.Build.Framework;
5+
using Microsoft.Build.Utilities;
6+
using Microsoft.Android.Build.Tasks;
7+
8+
namespace Xamarin.Android.Tasks;
9+
10+
class NativeLinker
11+
{
12+
readonly TaskLoggingHelper log;
13+
readonly string abi;
14+
15+
public NativeLinker (TaskLoggingHelper log, string abi)
16+
{
17+
this.log = log;
18+
this.abi = abi;
19+
}
20+
21+
public void Link (ITaskItem outputLibraryPath, List<ITaskItem> objectFiles, List<ITaskItem> archives)
22+
{
23+
log.LogDebugMessage ($"Linking: {outputLibraryPath}");
24+
EnsureCorrectAbi (outputLibraryPath);
25+
EnsureCorrectAbi (objectFiles);
26+
EnsureCorrectAbi (archives);
27+
}
28+
29+
void EnsureCorrectAbi (ITaskItem item)
30+
{
31+
// The exception is just a precaution, since the items passed to us should have already been checked
32+
string itemAbi = item.GetMetadata ("Abi") ?? throw new InvalidOperationException ($"Internal error: 'Abi' metadata not found in item '{item}'");
33+
if (String.Compare (abi, itemAbi, StringComparison.OrdinalIgnoreCase) == 0) {
34+
return;
35+
}
36+
37+
throw new InvalidOperationException ($"Internal error: '{item}' ABI ('{itemAbi}') doesn't have the expected value '{abi}'");
38+
}
39+
40+
void EnsureCorrectAbi (List<ITaskItem> items)
41+
{
42+
foreach (ITaskItem item in items) {
43+
EnsureCorrectAbi (item);
44+
}
45+
}
46+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
using Microsoft.Build.Framework;
5+
6+
namespace Xamarin.Android.Tasks;
7+
8+
class NativeRuntimeComponents
9+
{
10+
internal class Archive
11+
{
12+
public readonly string Name;
13+
public bool Include => shouldInclude (this);
14+
15+
Func<Archive, bool> shouldInclude;
16+
17+
public Archive (string name, Func<Archive, bool>? include = null)
18+
{
19+
Name = name;
20+
shouldInclude = include == null ? ((Archive arch) => true) : include;
21+
}
22+
}
23+
24+
internal class MonoComponentArchive : Archive
25+
{
26+
public readonly string ComponentName;
27+
28+
public MonoComponentArchive (string name, string componentName, Func<Archive, bool> include)
29+
: base (name, include)
30+
{
31+
ComponentName = componentName;
32+
}
33+
}
34+
35+
readonly ITaskItem[] monoComponents;
36+
37+
public readonly List<Archive> KnownArchives;
38+
39+
public NativeRuntimeComponents (ITaskItem[] monoComponents)
40+
{
41+
this.monoComponents = monoComponents;
42+
KnownArchives = new () {
43+
new MonoComponentArchive ("libmono-component-diagnostics_tracing-static.a", "diagnostics_tracing", MonoComponentPresent),
44+
new MonoComponentArchive ("libmono-component-diagnostics_tracing-stub-static.a", "diagnostics_tracing", MonoComponentAbsent),
45+
new MonoComponentArchive ("libmono-component-marshal-ilgen-static.a", "marshal-ilgen", MonoComponentPresent),
46+
new MonoComponentArchive ("libmono-component-marshal-ilgen-stub-static.a", "marshal-ilgen", MonoComponentAbsent),
47+
48+
new Archive ("libmonosgen-2.0.a"),
49+
new Archive ("libSystem.Globalization.Native.a"),
50+
new Archive ("libSystem.IO.Compression.Native.a"),
51+
new Archive ("libSystem.Native.a"),
52+
new Archive ("libSystem.Security.Cryptography.Native.Android.a"),
53+
};
54+
}
55+
56+
bool MonoComponentExists (Archive archive)
57+
{
58+
if (monoComponents.Length == 0) {
59+
return false;
60+
}
61+
62+
var mcArchive = archive as MonoComponentArchive;
63+
if (mcArchive == null) {
64+
throw new ArgumentException (nameof (archive), "Must be an instance of MonoComponentArchive");
65+
}
66+
67+
foreach (ITaskItem item in monoComponents) {
68+
if (String.Compare (item.ItemSpec, mcArchive.ComponentName, StringComparison.OrdinalIgnoreCase) == 0) {
69+
return true;
70+
}
71+
}
72+
73+
return false;
74+
}
75+
76+
bool MonoComponentAbsent (Archive archive)
77+
{
78+
return !MonoComponentExists (archive);
79+
}
80+
81+
bool MonoComponentPresent (Archive archive)
82+
{
83+
return MonoComponentExists (archive);
84+
}
85+
}

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2007,7 +2007,8 @@ because xbuild doesn't support framework reference assemblies.
20072007
<Target Name="_CreateApplicationSharedLibraries"
20082008
DependsOnTargets="_CompileNativeAssemblySources;_PrepareApplicationSharedLibraryItems"
20092009
Inputs="@(_NativeAssemblyTarget)"
2010-
Outputs="@(_ApplicationSharedLibrary)">
2010+
Outputs="@(_ApplicationSharedLibrary)"
2011+
Condition=" '$(_AndroidEnableNativeRuntimeLinking)' != 'true' ">
20112012
<LinkApplicationSharedLibraries
20122013
ObjectFiles="@(_NativeAssemblyTarget)"
20132014
ApplicationSharedLibraries="@(_ApplicationSharedLibrary)"

0 commit comments

Comments
 (0)