Skip to content

Commit 8372461

Browse files
authored
[native] Common infrastructure for native shared library linking (#9990)
Context: #9938 PR #9938 is an attempt to build `libnet-android.Debug.so` and `libnet-android.Release.so` so that CoreCLR is *statically linked* in to `libnet-android*.so`. This reduces the number of native libraries that must be placed into the `.apk`, and allows the `.apk` to be smaller, as the native linker can remove unused code. *Note*: CoreCLR is ***not*** yet statically linked into `libnet-android*.so`. This is *preliminary* work to support that. This iteration of static linking also requires that *all* symbols be resolvable, by requiring `lld --no-undefined` by default. This in turn requires that we ship *copies* of `libc.so` et al, so that *all* symbols needed by `libnet-android*.so` can be resolved, including those from the Android NDK. Update `build-tools/xaprepare` to extract required native libraries from the NDK, and add those to the .NET for Android Workload packs. Update `Xamarin.Android.Build.Tasks.dll` to cleanup and refactor `ld` invocation, so that `libnet-android*.so` is built with `ld --no-undefined`. This makes it easier to maintain and update the linker code in the future, as well as ensures that we use consistent linking flags across the board. Updates the LLVM IR code generator bits, also extracted from #9938, which aren't strictly related to native linking, but they are placed here in order to make #9938 smaller.
1 parent 4eafe66 commit 8372461

25 files changed

+872
-319
lines changed

Configuration.props

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@
228228
AndroidRuntime="CoreCLR" />
229229
</ItemGroup>
230230

231+
<PropertyGroup>
232+
<_RuntimeRedistDirName>redist</_RuntimeRedistDirName>
233+
</PropertyGroup>
234+
231235
<!-- Whenever there's a need to use a locally built CoreCLR, both .NET for Android and the
232236
application(s) must be built with the same runtime. CLRLocalRuntimePath must point to the CoreCLR
233237
artifact directory in its repository checkout:

build-tools/create-packs/Microsoft.Android.Runtime.proj

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,11 @@ projects that use the Microsoft.Android.Runtimes framework in .NET 6+.
6363
</ItemGroup>
6464

6565
<ItemGroup Condition=" '$(AndroidRuntime)' != 'NativeAOT' ">
66-
<!-- TODO: the Exists() checks must go away once we build CoreCLR host for all the targets -->
67-
<NativeRuntimeAsset Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libc.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libc.so" />
68-
<NativeRuntimeAsset Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libdl.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libdl.so" />
69-
<NativeRuntimeAsset Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\liblog.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\liblog.so" />
70-
<NativeRuntimeAsset Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libm.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libm.so" />
71-
<NativeRuntimeAsset Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libz.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libz.so" />
66+
<NativeRuntimeAsset Include="$(NativeRuntimeOutputRootDir)$(_RuntimeRedistDirName)\$(AndroidRID)\libc.so" />
67+
<NativeRuntimeAsset Include="$(NativeRuntimeOutputRootDir)$(_RuntimeRedistDirName)\$(AndroidRID)\libdl.so" />
68+
<NativeRuntimeAsset Include="$(NativeRuntimeOutputRootDir)$(_RuntimeRedistDirName)\$(AndroidRID)\liblog.so" />
69+
<NativeRuntimeAsset Include="$(NativeRuntimeOutputRootDir)$(_RuntimeRedistDirName)\$(AndroidRID)\libm.so" />
70+
<NativeRuntimeAsset Include="$(NativeRuntimeOutputRootDir)$(_RuntimeRedistDirName)\$(AndroidRID)\libz.so" />
7271
<NativeRuntimeAsset Condition=" Exists('$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libarchive-dso-stub.so') " Include="$(NativeRuntimeOutputRootDir)$(_RuntimeFlavorDirName)\$(AndroidRID)\libarchive-dso-stub.so" />
7372
</ItemGroup>
7473

build-tools/xaprepare/xaprepare/Application/KnownProperties.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,12 @@ static class KnownProperties
4747
public const string MonoRequiredMinimumVersion = "MonoRequiredMinimumVersion";
4848
public const string MonoRequiredMaximumVersion = "MonoRequiredMaximumVersion";
4949
public const string MonoSourceFullPath = "MonoSourceFullPath";
50+
public const string NativeRuntimeOutputRootDir = "NativeRuntimeOutputRootDir";
5051
public const string NinjaPath = "NinjaPath";
5152
public const string Pkg7Zip_CommandLine = "Pkg7-Zip_CommandLine";
5253
public const string PkgXamarin_LibZipSharp = "PkgXamarin_LibZipSharp";
5354
public const string ProductVersion = "ProductVersion";
55+
public const string RuntimeRedistDirName = "_RuntimeRedistDirName";
5456
public const string XABuildToolsFolder = "XABuildToolsFolder";
5557
public const string XABuildToolsVersion = "XABuildToolsVersion";
5658
public const string XABuildToolsPackagePrefixMacOS = "XABuildToolsPackagePrefixMacOS";

build-tools/xaprepare/xaprepare/Application/Properties.Defaults.cs.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,12 @@ namespace Xamarin.Android.Prepare
5151
properties.Add (KnownProperties.MonoRequiredMinimumVersion, StripQuotes ("@MonoRequiredMinimumVersion@"));
5252
properties.Add (KnownProperties.MonoRequiredMaximumVersion, StripQuotes ("@MonoRequiredMaximumVersion@"));
5353
properties.Add (KnownProperties.MonoSourceFullPath, StripQuotes (@"@MonoSourceFullPath@"));
54+
properties.Add (KnownProperties.NativeRuntimeOutputRootDir, StripQuotes (@"@NativeRuntimeOutputRootDir@"));
5455
properties.Add (KnownProperties.NinjaPath, StripQuotes (@"@NinjaPath@"));
5556
properties.Add (KnownProperties.Pkg7Zip_CommandLine, StripQuotes (@"@Pkg7-Zip_CommandLine@"));
5657
properties.Add (KnownProperties.PkgXamarin_LibZipSharp, StripQuotes (@"@PkgXamarin_LibZipSharp@"));
5758
properties.Add (KnownProperties.ProductVersion, StripQuotes ("@ProductVersion@"));
59+
properties.Add (KnownProperties.RuntimeRedistDirName, StripQuotes ("@_RuntimeRedistDirName@"));
5860
properties.Add (KnownProperties.XABuildToolsFolder, StripQuotes (@"@XABuildToolsFolder@"));
5961
properties.Add (KnownProperties.XABuildToolsVersion, StripQuotes ("@XABuildToolsVersion@"));
6062
properties.Add (KnownProperties.XABuildToolsPackagePrefixMacOS, StripQuotes ("@XABuildToolsPackagePrefixMacOS@"));

build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ public static partial class Defaults
147147
{ "x86_64", "x86_64-linux-android" },
148148
};
149149

150+
public static readonly Dictionary<string, string> AbiToRID = new (StringComparer.Ordinal) {
151+
{ "armeabi-v7a", "android-arm" },
152+
{ "arm64-v8a", "android-arm64" },
153+
{ "x86", "android-x86" },
154+
{ "x86_64", "android-x64" },
155+
};
156+
150157
public static readonly List <NDKTool> NDKTools = new List<NDKTool> {
151158
// Tools prefixed with architecture triple
152159
new NDKTool (name: "as", prefixed: true),

build-tools/xaprepare/xaprepare/Steps/Step_Android_SDK_NDK.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4+
using System.Globalization;
45
using System.IO;
56
using System.Linq;
67
using System.Threading.Tasks;
@@ -22,6 +23,14 @@ sealed class AndroidPackage
2223
}
2324
#nullable enable
2425

26+
static readonly string[] CRTFiles = {
27+
"libc.so",
28+
"libdl.so",
29+
"liblog.so",
30+
"libm.so",
31+
"libz.so",
32+
};
33+
2534
bool RefreshSdk = false;
2635
bool RefreshNdk = false;
2736
AndroidToolchainComponentType DependencyTypeToInstall = AndroidToolchainComponentType.All;
@@ -151,13 +160,62 @@ bool AcceptLicenses (Context context, string sdkRoot)
151160

152161
bool GatherNDKInfo (Context context)
153162
{
163+
if (!CopyRedistributableFiles (context)) {
164+
return false;
165+
}
166+
154167
// Ignore NDK property setting if not installing the NDK
155168
if (!DependencyTypeToInstall.HasFlag (AndroidToolchainComponentType.BuildDependency))
156169
return true;
157170
else
158171
return context.BuildInfo.GatherNDKInfo (context);
159172
}
160173

174+
bool CopyRedistributableFiles (Context context)
175+
{
176+
string androidVersionPath = Path.Combine (Configurables.Paths.AndroidToolchainRootDirectory, "AndroidVersion.txt");
177+
if (!File.Exists (androidVersionPath)) {
178+
throw new InvalidOperationException ($"Android version file '{androidVersionPath}' not found");
179+
}
180+
181+
string[]? lines = File.ReadAllLines (androidVersionPath);
182+
if (lines == null || lines.Length < 1) {
183+
throw new InvalidOperationException ($"Unknown format of Android version file '{androidVersionPath}'");
184+
}
185+
186+
// First line is (should be) the LLVM version, we need just the main release number
187+
string[] llvmVersion = lines[0].Split ('.');
188+
if (llvmVersion.Length < 3) {
189+
throw new InvalidOperationException ($"Unknown LLVM version format for '{lines[0]}'");
190+
}
191+
192+
foreach (var kvp in Configurables.Defaults.AndroidToolchainPrefixes) {
193+
string abi = kvp.Key;
194+
string abiDir = Path.Combine (Configurables.Paths.AndroidToolchainSysrootLibDirectory, kvp.Value);
195+
string crtFilesPath = Path.Combine (abiDir, BuildAndroidPlatforms.NdkMinimumAPI.ToString (CultureInfo.InvariantCulture));
196+
197+
foreach (string file in CRTFiles) {
198+
CopyFile (abi, crtFilesPath, file);
199+
}
200+
}
201+
202+
return true;
203+
204+
void CopyFile (string abi, string sourceDir, string fileName)
205+
{
206+
Log.StatusLine ($" {context.Characters.Bullet} Copying NDK redistributable: ", $"{fileName} ({abi})", tailColor: ConsoleColor.White);
207+
string rid = Configurables.Defaults.AbiToRID [abi];
208+
string outputDir = Path.Combine (
209+
context.Properties.GetRequiredValue (KnownProperties.NativeRuntimeOutputRootDir),
210+
context.Properties.GetRequiredValue (KnownProperties.RuntimeRedistDirName),
211+
rid
212+
);
213+
214+
string sourceFile = Path.Combine (sourceDir, fileName);
215+
Utilities.CopyFileToDir (sourceFile, outputDir);
216+
}
217+
}
218+
161219
void CheckPackageStatus (Context context, string packageCacheDir, AndroidPackage pkg, List <AndroidPackage> toDownload)
162220
{
163221
Log.StatusLine ($" {context.Characters.Bullet} Installing ", pkg.Component.Name, tailColor: ConsoleColor.White);

build-tools/xaprepare/xaprepare/xaprepare.targets

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,12 @@
8484
<Replacement Include="@MonoRequiredMinimumVersion@=$(MonoRequiredMinimumVersion)" />
8585
<Replacement Include="@MonoRequiredMaximumVersion@=$(MonoRequiredMaximumVersion)" />
8686
<Replacement Include="@MonoSourceFullPath@=$(MonoSourceFullPath)" />
87+
<Replacement Include="@NativeRuntimeOutputRootDir@=$(NativeRuntimeOutputRootDir)" />
8788
<Replacement Include="@NinjaPath@=$(NinjaPath)" />
8889
<Replacement Include="@Pkg7-Zip_CommandLine@=$(Pkg7-Zip_CommandLine)" />
8990
<Replacement Include="@PkgXamarin_LibZipSharp@=$(PkgXamarin_LibZipSharp)" />
9091
<Replacement Include="@ProductVersion@=$(ProductVersion)" />
92+
<Replacement Include="@_RuntimeRedistDirName@=$(_RuntimeRedistDirName)" />
9193
<Replacement Include="@XABuildToolsFolder@=$(XABuildToolsFolder)" />
9294
<Replacement Include="@XABuildToolsVersion@=$(XABuildToolsVersion)" />
9395
<Replacement Include="@XABuildToolsPackagePrefixMacOS@=$(XABuildToolsPackagePrefixMacOS)" />

0 commit comments

Comments
 (0)