Skip to content

Commit fc3f028

Browse files
authored
[build] Use own build of GNU Binutils (#5887)
Context: https://github.com/android/ndk/wiki/Changelog-r23#announcements Context: https://github.com/grendello/xamarin-android-binutils Starting with Android NDK r23, the Android NDK will stop distributing the GNU Binutils binaries which Xamarin.Android needs in order to build applications. The utilities are `as`, `ld`, and `strip`, and were previously extracted by `xaprepare` from the Android NDK archives. Instead of relying on the Android NDK to build the GNU Binutils, we have created a separate repo to build them: * https://github.com/grendello/xamarin-android-binutils Begin using the binaries built in the xamarin-android-binutils repo. This commit stops using the `Step_Get_Windows_Binutils` step which was previously used to remotely extract Windows binaries from the Android NDK archive without fully downloading it, but it does not remove the source, since it may become useful in the future to extract the Windows version of `aapt2` in the same manner.
1 parent d3ae4e1 commit fc3f028

17 files changed

+1689
-1570
lines changed

build-tools/create-packs/SignList.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
<ThirdParty Include="x86_64-linux-android-as.exe" />
2727
<ThirdParty Include="x86_64-linux-android-ld.exe" />
2828
<ThirdParty Include="x86_64-linux-android-strip.exe" />
29-
<ThirdParty Include="libwinpthread-1.dll" />
3029
</ItemGroup>
3130

3231
<ItemGroup>

build-tools/installers/create-installers.targets

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,6 @@
322322
<_MSBuildFilesWin Include="$(MSBuildSrcDir)\ndk\x86_64-linux-android-as.exe" />
323323
<_MSBuildFilesWin Include="$(MSBuildSrcDir)\ndk\x86_64-linux-android-ld.exe" />
324324
<_MSBuildFilesWin Include="$(MSBuildSrcDir)\ndk\x86_64-linux-android-strip.exe" />
325-
<_MSBuildFilesWin Include="$(MSBuildSrcDir)\ndk\libwinpthread-1.dll" />
326325
<_MSBuildLibHostFilesWin Include="$(MSBuildSrcDir)\lib\host-mxe-Win64\libmono-android.debug.dll" Condition=" '$(HostOS)' != 'Windows' " />
327326
<_MSBuildLibHostFilesWin Include="$(MSBuildSrcDir)\lib\host-mxe-Win64\libmono-android.release.dll" Condition=" '$(HostOS)' != 'Windows' " />
328327
<_MSBuildLibHostFilesWin Include="$(MSBuildSrcDir)\lib\host-mxe-Win64\libMonoPosixHelper.dll" />

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ namespace Xamarin.Android.Prepare
1515
//
1616
partial class Configurables
1717
{
18+
const string BinutilsVersion = "2.36.1-XA.4";
19+
1820
const string MicrosoftOpenJDK11Version = "11.0.10";
1921
const string MicrosoftOpenJDK11Release = "9.1";
2022
const string MicrosoftOpenJDK11RootDirName = "jdk-11.0.10+9";
@@ -50,10 +52,13 @@ public static partial class Urls
5052
public static readonly Uri NugetUri = new Uri ("https://dist.nuget.org/win-x86-commandline/v4.9.4/nuget.exe");
5153

5254
public static Uri MonoArchive_BaseUri = new Uri ("https://xamjenkinsartifact.azureedge.net/mono-sdks/");
55+
56+
public static Uri BinutilsArchive = new Uri ($"https://github.com/grendello/xamarin-android-binutils/releases/download/{BinutilsVersion}/xamarin-android-binutils-{BinutilsVersion}.7z");
5357
}
5458

5559
public static partial class Defaults
5660
{
61+
public static readonly string BinutilsVersion = Configurables.BinutilsVersion;
5762
public static readonly char[] PropertyListSeparator = new [] { ':' };
5863

5964
public static readonly string JdkFolder = "jdk-11";
@@ -271,7 +276,7 @@ public static partial class Defaults
271276

272277
public static readonly List <NDKTool> NDKTools = new List<NDKTool> {
273278
new NDKTool (name: "as"),
274-
new NDKTool (name: "ld.gold", destinationName: "ld"),
279+
new NDKTool (name: "ld"),
275280
new NDKTool (name: "strip"),
276281
};
277282
}
@@ -388,6 +393,7 @@ public static partial class Paths
388393
public static string AndroidToolchainSysrootLibDirectory => GetCachedPath (ref androidToolchainSysrootLibDirectory, () => Path.Combine (AndroidToolchainRootDirectory, "sysroot", "usr", "lib"));
389394
public static string WindowsBinutilsInstallDir => GetCachedPath (ref windowsBinutilsInstallDir, () => Path.Combine (InstallMSBuildDir, "ndk"));
390395
public static string HostBinutilsInstallDir => GetCachedPath (ref hostBinutilsInstallDir, () => Path.Combine (InstallMSBuildDir, ctx.Properties.GetRequiredValue (KnownProperties.HostOS), "ndk"));
396+
public static string BinutilsCacheDir => ctx.Properties.GetRequiredValue (KnownProperties.AndroidToolchainCacheDirectory);
391397

392398
// not really configurables, merely convenience aliases for more frequently used paths that come from properties
393399
public static string XAInstallPrefix => ctx.Properties.GetRequiredValue (KnownProperties.XAInstallPrefix);

build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.Unix.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,6 @@ partial void AddRequiredOSSpecificSteps (bool beforeBundle)
99
{
1010
AddRequiredMacOSSteps (beforeBundle);
1111

12-
if (!beforeBundle) {
13-
// It has to go after the bundle step because bundle unpacking or creation *always* cleans its
14-
// destination directory and this is where we download the GAS binaries. They are not part of the bundle
15-
// (because they're not useful for every day work with XA) so they must be downloaded after the bundle
16-
// is unpacked.
17-
Log.DebugLine ("Adding Windows GAS download step (AFTER bundle)");
18-
Steps.Add (new Step_Get_Windows_Binutils ());
19-
return;
20-
}
21-
2212
if (Context.Instance.WindowsJitAbisEnabled) {
2313
Log.DebugLine ("Windows JIT ABIs ENABLED, ADDING MinGW dependencies build step (BEFORE bundle)");
2414
Steps.Add (new Step_BuildMingwDependencies ());

build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ protected override void AddSteps (Context context)
3434

3535
// The next two steps MUST be after InstallMonoRuntimes above since the latter cleans up the target
3636
// directory where the NDK binutils are installed
37-
Steps.Add (new Step_InstallNDKBinutils ());
38-
Steps.Add (new Step_Get_Windows_Binutils ());
37+
Steps.Add (new Step_InstallGNUBinutils ());
3938
Steps.Add (new Step_GenerateCGManifest ());
4039

4140
AddRequiredOSSpecificSteps (false);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Xamarin.Android.Prepare
2+
{
3+
partial class Step_InstallGNUBinutils
4+
{
5+
const string HostName = "linux";
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Xamarin.Android.Prepare
2+
{
3+
partial class Step_InstallGNUBinutils
4+
{
5+
const string HostName = "darwin";
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Xamarin.Android.Prepare
2+
{
3+
partial class Step_InstallGNUBinutils
4+
{
5+
const string? ExecutableExtension = null;
6+
}
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Xamarin.Android.Prepare
2+
{
3+
partial class Step_InstallGNUBinutils
4+
{
5+
const string HostName = "windows";
6+
const string ExecutableExtension = ".exe";
7+
}
8+
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
using System;
2+
using System.IO;
3+
using System.Net;
4+
using System.Threading.Tasks;
5+
6+
namespace Xamarin.Android.Prepare
7+
{
8+
partial class Step_InstallGNUBinutils : StepWithDownloadProgress
9+
{
10+
static readonly string ProductName = $"GNU Binutils {Configurables.Defaults.BinutilsVersion}";
11+
12+
public Step_InstallGNUBinutils ()
13+
: base ("Install GNU Binutils")
14+
{}
15+
16+
protected override async Task<bool> Execute (Context context)
17+
{
18+
string hostDestinationDirectory = Configurables.Paths.HostBinutilsInstallDir;
19+
string windowsDestinationDirectory = Configurables.Paths.WindowsBinutilsInstallDir;
20+
21+
bool hostHaveAll = HaveAllBinutils (hostDestinationDirectory);
22+
bool windowsHaveAll = HaveAllBinutils (windowsDestinationDirectory, ".exe");
23+
24+
if (hostHaveAll && windowsHaveAll) {
25+
Log.StatusLine ("All Binutils are already installed");
26+
return true;
27+
}
28+
29+
string packageName = Path.GetFileName (Configurables.Urls.BinutilsArchive.LocalPath);
30+
string localArchivePath = Path.Combine (Configurables.Paths.BinutilsCacheDir, packageName);
31+
32+
if (!await DownloadBinutils (context, localArchivePath, Configurables.Urls.BinutilsArchive)) {
33+
return false;
34+
}
35+
36+
string tempDir = Path.Combine (Path.GetTempPath (), "xaprepare-binutils");
37+
Utilities.DeleteDirectorySilent (tempDir);
38+
Utilities.CreateDirectory (tempDir);
39+
40+
Log.DebugLine ($"Unpacking {ProductName} archive {localArchivePath} into {tempDir}");
41+
if (!await Utilities.Unpack (localArchivePath, tempDir, cleanDestinatioBeforeUnpacking: true)) {
42+
return false;
43+
}
44+
45+
if (!hostHaveAll) {
46+
CopyToDestination (context, "Host", tempDir, hostDestinationDirectory, executableExtension: ExecutableExtension);
47+
}
48+
49+
if (!windowsHaveAll) {
50+
CopyToDestination (context, "Windows", tempDir, windowsDestinationDirectory, "windows", ".exe");
51+
}
52+
53+
return true;
54+
}
55+
56+
bool CopyToDestination (Context context, string label, string sourceDir, string destinationDir, string osName = HostName, string? executableExtension = null)
57+
{
58+
Log.StatusLine ();
59+
Log.StatusLine ($"Installing for {label}:");
60+
61+
string sourcePath = Path.Combine (sourceDir, osName);
62+
foreach (var kvp in Configurables.Defaults.AndroidToolchainPrefixes) {
63+
string prefix = kvp.Value;
64+
65+
foreach (NDKTool tool in Configurables.Defaults.NDKTools) {
66+
string toolName = GetToolName (prefix, tool, executableExtension);
67+
string toolSourcePath = Path.Combine (sourcePath, toolName);
68+
string toolDestinationPath = Path.Combine (destinationDir, toolName);
69+
string versionMarkerPath = GetVersionMarker (toolDestinationPath);
70+
71+
Log.StatusLine ($" {context.Characters.Bullet} Installing ", toolName, tailColor: ConsoleColor.White);
72+
Utilities.CopyFile (toolSourcePath, toolDestinationPath);
73+
File.WriteAllText (versionMarkerPath, DateTime.UtcNow.ToString ());
74+
}
75+
}
76+
77+
return true;
78+
}
79+
80+
async Task<bool> DownloadBinutils (Context context, string localPackagePath, Uri url)
81+
{
82+
if (Utilities.FileExists (localPackagePath)) {
83+
Log.StatusLine ($"{ProductName} archive already downloaded");
84+
return true;
85+
}
86+
87+
Log.StatusLine ($"Downloading {ProductName} from ", url.ToString (), tailColor: ConsoleColor.White);
88+
(bool success, ulong size, HttpStatusCode status) = await Utilities.GetDownloadSizeWithStatus (url);
89+
if (!success) {
90+
if (status == HttpStatusCode.NotFound) {
91+
Log.ErrorLine ($"{ProductName} archive URL not found");
92+
return false;
93+
}
94+
Log.WarningLine ($"Failed to obtain {ProductName} size. HTTP status code: {status} ({(int)status})");
95+
}
96+
97+
DownloadStatus downloadStatus = Utilities.SetupDownloadStatus (context, size, context.InteractiveSession);
98+
Log.StatusLine ($" {context.Characters.Link} {url}", ConsoleColor.White);
99+
await Download (context, url, localPackagePath, ProductName, Path.GetFileName (localPackagePath), downloadStatus);
100+
101+
if (!File.Exists (localPackagePath)) {
102+
Log.ErrorLine ($"Download of {ProductName} from {url} failed.");
103+
return false;
104+
}
105+
106+
return true;
107+
}
108+
109+
bool HaveAllBinutils (string dir, string? executableExtension = null)
110+
{
111+
Log.DebugLine ("Checking if all binutils are installed in {dir}");
112+
string extension = executableExtension ?? String.Empty;
113+
foreach (var kvp in Configurables.Defaults.AndroidToolchainPrefixes) {
114+
string prefix = kvp.Value;
115+
116+
foreach (NDKTool tool in Configurables.Defaults.NDKTools) {
117+
string toolName = GetToolName (prefix, tool, executableExtension);
118+
string toolPath = Path.Combine (dir, toolName);
119+
string versionMarkerPath = GetVersionMarker (toolPath);
120+
121+
Log.DebugLine ($"Checking {toolName}");
122+
if (!Utilities.FileExists (toolPath)) {
123+
Log.DebugLine ($"Binutils tool {toolPath} does not exist");
124+
return false;
125+
}
126+
127+
if (!Utilities.FileExists (versionMarkerPath)) {
128+
Log.DebugLine ($"Binutils tool {toolPath} exists, but its version is incorrect");
129+
return false;
130+
}
131+
}
132+
}
133+
134+
return true;
135+
}
136+
137+
string GetToolName (string prefix, NDKTool tool, string? executableExtension = null)
138+
{
139+
return $"{prefix}-{(String.IsNullOrEmpty (tool.DestinationName) ? tool.Name : tool.DestinationName)}{executableExtension}";
140+
}
141+
142+
string GetVersionMarker (string toolPath)
143+
{
144+
return $"{toolPath}.{Configurables.Defaults.BinutilsVersion}";
145+
}
146+
}
147+
}

0 commit comments

Comments
 (0)