Skip to content

Commit

Permalink
Try to use local binutils for LLVM
Browse files Browse the repository at this point in the history
  • Loading branch information
pjcollins committed Apr 7, 2022
1 parent 3f2e55d commit dbe508e
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 151 deletions.
7 changes: 1 addition & 6 deletions src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ static string QuoteFileName(string fileName)

public async override System.Threading.Tasks.Task RunTaskAsync ()
{
NdkTools ndk = NdkTools.Create (AndroidNdkDirectory, logErrors: EnableLLVM, log: Log);
NdkTools ndk = NdkTools.Create (null, logErrors: false, log: Log);
if (Log.HasLoggedErrors) {
return; // NdkTools.Create will log appropriate error
}
Expand Down Expand Up @@ -114,11 +114,6 @@ IEnumerable<Config> GetAotConfigs (NdkTools ndk)
foreach (var abi in SupportedAbis) {
(string aotCompiler, string outdir, string mtriple, AndroidTargetArch arch) = GetAbiSettings (abi);

if (EnableLLVM && !ndk.ValidateNdkPlatform (LogMessage, LogCodedError, arch, enableLLVM:EnableLLVM)) {
yield return Config.Invalid;
yield break;
}

outdir = Path.GetFullPath (outdir);
if (!Directory.Exists (outdir))
Directory.CreateDirectory (outdir);
Expand Down
111 changes: 6 additions & 105 deletions src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,7 @@ public static bool TryGetSequencePointsMode (string value, out SequencePointsMod
protected string GetToolPrefix (NdkTools ndk, AndroidTargetArch arch, out int level)
{
level = 0;
return EnableLLVM
? ndk.GetNdkToolPrefixForAOT (arch, level = GetNdkApiLevel (ndk, arch))
: Path.Combine (AndroidBinUtilsDirectory, $"{ndk.GetArchDirName (arch)}-");
return Path.Combine (AndroidBinUtilsDirectory, $"{ndk.GetArchDirName (arch)}-");
}

int GetNdkApiLevel (NdkTools ndk, AndroidTargetArch arch)
Expand Down Expand Up @@ -228,120 +226,23 @@ protected void GetAotOptions (NdkTools ndk, AndroidTargetArch arch, int level, s
if (SequencePointsMode == SequencePointsMode.Offline)
MsymPath = outdir;

string ldName;
if (EnableLLVM) {
ldName = ndk.GetToolPath (NdkToolKind.Linker, arch, level);
if (!string.IsNullOrEmpty (ldName)) {
ldName = Path.GetFileName (ldName);
if (ldName.IndexOf ('-') >= 0) {
ldName = ldName.Substring (ldName.LastIndexOf ("-", StringComparison.Ordinal) + 1);
}
}
} else {
ldName = "ld";
}
LdName = "ld";

string ldFlags = GetLdFlags (ndk, arch, level, toolPrefix);
if (!string.IsNullOrEmpty (ldName)) {
LdName = ldName;
}
if (!string.IsNullOrEmpty (ldFlags)) {
LdFlags = ldFlags;
}
}

string GetLdFlags(NdkTools ndk, AndroidTargetArch arch, int level, string toolPrefix)
string GetLdFlags (NdkTools ndk, AndroidTargetArch arch, int level, string toolPrefix)
{
var toolchainPath = toolPrefix.Substring (0, toolPrefix.LastIndexOf (Path.DirectorySeparatorChar));
var ldFlags = string.Empty;
if (EnableLLVM) {
string androidLibPath = string.Empty;
try {
androidLibPath = ndk.GetDirectoryPath (NdkToolchainDir.PlatformLib, arch, level);
} catch (InvalidOperationException ex) {
Diagnostic.Error (5101, ex.Message);
}

string toolchainLibDir;
if (ndk.UsesClang) {
if (ndk.NoBinutils) {
toolchainLibDir = String.Empty;
} else {
toolchainLibDir = GetNdkToolchainLibraryDir (ndk, toolchainPath, arch);
}
} else
toolchainLibDir = GetNdkToolchainLibraryDir (ndk, toolchainPath);

var libs = new List<string> ();
if (ndk.UsesClang) {
if (!String.IsNullOrEmpty (toolchainLibDir)) {
libs.Add ($"-L{toolchainLibDir.TrimEnd ('\\')}");
}
libs.Add ($"-L{androidLibPath.TrimEnd ('\\')}");

if (arch == AndroidTargetArch.Arm) {
// Needed for -lunwind to work
string compilerLibDir = Path.Combine (toolchainPath, "..", "sysroot", "usr", "lib", ndk.GetArchDirName (arch));
libs.Add ($"-L{compilerLibDir.TrimEnd ('\\')}");
}
}

if (!String.IsNullOrEmpty (toolchainLibDir)) {
libs.Add (Path.Combine (toolchainLibDir, "libgcc.a"));
}
libs.Add (Path.Combine (androidLibPath, "libc.so"));
libs.Add (Path.Combine (androidLibPath, "libm.so"));

ldFlags = $"\\\"{string.Join ("\\\";\\\"", libs)}\\\"";
}

if (!StripLibraries) {
return ldFlags;
}

const string StripFlag = "-s";
if (ldFlags.Length == 0) {
if (StripLibraries) {
return StripFlag;
}

return $"{ldFlags} {StripFlag}";
}

static string GetNdkToolchainLibraryDir (NdkTools ndk, string binDir, string archDir = null)
{
var baseDir = Path.GetFullPath (Path.Combine (binDir, ".."));

string libDir = Path.Combine (baseDir, "lib", "gcc");
if (!String.IsNullOrEmpty (archDir))
libDir = Path.Combine (libDir, archDir);

var gccLibDir = Directory.EnumerateDirectories (libDir).ToList ();
gccLibDir.Sort ();

var libPath = gccLibDir.LastOrDefault ();
if (libPath == null) {
goto no_toolchain_error;
}

if (ndk.UsesClang)
return libPath;

gccLibDir = Directory.EnumerateDirectories (libPath).ToList ();
gccLibDir.Sort ();

libPath = gccLibDir.LastOrDefault ();
if (libPath == null) {
goto no_toolchain_error;
}

return libPath;

no_toolchain_error:
throw new Exception ("Could not find a valid NDK compiler toolchain library path");
return string.Empty;
}

static string GetNdkToolchainLibraryDir (NdkTools ndk, string binDir, AndroidTargetArch arch)
{
return GetNdkToolchainLibraryDir (ndk, binDir, ndk.GetArchDirName (arch));
}
}
}
2 changes: 1 addition & 1 deletion src/Xamarin.Android.Build.Tasks/Tasks/GetAotAssemblies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class GetAotAssemblies : GetAotArguments

public override Task RunTaskAsync ()
{
NdkTools ndk = NdkTools.Create (AndroidNdkDirectory, logErrors: EnableLLVM, log: Log);
NdkTools ndk = NdkTools.Create (null, logErrors: false, log: Log);
if (Log.HasLoggedErrors) {
return Task.CompletedTask; // NdkTools.Create will log appropriate error
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,64 +110,55 @@ public void BuildBasicApplicationReleaseProfiledAotWithoutDefaultProfile ()
new object[] {
/* supportedAbis */ "armeabi-v7a",
/* enableLLVM */ false,
/* expectedResult */ true,
/* usesAssemblyBlobs */ false,
},
new object[] {
/* supportedAbis */ "armeabi-v7a",
/* enableLLVM */ false,
/* expectedResult */ true,
/* usesAssemblyBlobs */ true,
},
new object[] {
/* supportedAbis */ "armeabi-v7a",
/* enableLLVM */ true,
/* expectedResult */ true,
/* usesAssemblyBlobs */ false,
},
new object[] {
/* supportedAbis */ "arm64-v8a",
/* enableLLVM */ false,
/* expectedResult */ true,
/* usesAssemblyBlobs */ false,
},
new object[] {
/* supportedAbis */ "arm64-v8a",
/* enableLLVM */ true,
/* expectedResult */ true,
/* usesAssemblyBlobs */ false,
},
new object[] {
/* supportedAbis */ "x86",
/* enableLLVM */ false,
/* expectedResult */ true,
/* usesAssemblyBlobs */ false,
},
new object[] {
/* supportedAbis */ "x86",
/* enableLLVM */ true,
/* expectedResult */ true,
/* usesAssemblyBlobs */ false,
},
new object[] {
/* supportedAbis */ "x86_64",
/* enableLLVM */ false,
/* expectedResult */ true,
/* usesAssemblyBlobs */ false,
},
new object[] {
/* supportedAbis */ "x86_64",
/* enableLLVM */ true,
/* expectedResult */ true,
/* usesAssemblyBlobs */ false,
},
};

[Test]
[TestCaseSource (nameof (AotChecks))]
public void BuildAotApplicationAndÜmläüts (string supportedAbis, bool enableLLVM, bool expectedResult, bool usesAssemblyBlobs)
public void BuildAotApplicationAndÜmläüts (string supportedAbis, bool enableLLVM, bool usesAssemblyBlobs)
{
var path = Path.Combine ("temp", string.Format ("BuildAotApplication AndÜmläüts_{0}_{1}_{2}_{3}", supportedAbis, enableLLVM, expectedResult, usesAssemblyBlobs));
var path = Path.Combine ("temp", string.Format ("BuildAotApplication AndÜmläüts_{0}_{1}_{2}", supportedAbis, enableLLVM, usesAssemblyBlobs));
var proj = new XamarinAndroidApplicationProject () {
IsRelease = true,
BundleAssemblies = false,
Expand All @@ -194,24 +185,7 @@ public void BuildAotApplicationAndÜmläüts (string supportedAbis, bool enableL
if (!b.GetSupportedRuntimes ().Any (x => supportedAbis == x.Abi))
Assert.Ignore ($"Runtime for {supportedAbis} was not available.");
b.ThrowOnBuildFailure = false;
Assert.AreEqual (expectedResult, b.Build (proj), "Build should have {0}.", expectedResult ? "succeeded" : "failed");
if (!expectedResult)
return;
//NOTE: Windows has shortened paths such as: C:\Users\myuser\ANDROI~3\ndk\PLATFO~1\AN3971~1\arch-x86\usr\lib\libc.so
if (checkMinLlvmPath && !IsWindows && !Builder.UseDotNet) {
Xamarin.Android.Tasks.NdkTools ndk = Xamarin.Android.Tasks.NdkTools.Create (AndroidNdkPath);
bool ndk22OrNewer = ndk.Version.Main.Major >= 22;

// LLVM passes a direct path to libc.so, and we need to use the libc.so
// which corresponds to the *minimum* SDK version specified in AndroidManifest.xml
// Since we overrode minSdkVersion=16, that means we should use libc.so from android-16.
if (ndk22OrNewer) {
// NDK r22 or newer store libc in [toolchain]/sysroot/usr/lib/[ARCH]/[API]/libc.so
StringAssertEx.ContainsRegex (@"\s*\[aot-compiler stdout].*sysroot.*.usr.lib.*19.libc\.so", b.LastBuildOutput, "AOT+LLVM should use libc.so from minSdkVersion!");
} else {
StringAssertEx.ContainsRegex (@"\s*\[aot-compiler stdout].*android-19.arch-.*.usr.lib.libc\.so", b.LastBuildOutput, "AOT+LLVM should use libc.so from minSdkVersion!");
}
}
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
foreach (var abi in supportedAbis.Split (new char [] { ';' })) {
var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);
var libapp = Path.Combine (intermediate, "bundles", abi, "libmonodroid_bundle_app.so");
Expand All @@ -231,7 +205,7 @@ public void BuildAotApplicationAndÜmläüts (string supportedAbis, bool enableL
$"lib/{0}/libaot-UnnamedProject.dll.so should be in the {proj.PackageName}-Signed.apk", abi);
}
}
Assert.AreEqual (expectedResult, b.Build (proj), "Second Build should have {0}.", expectedResult ? "succeeded" : "failed");
Assert.IsTrue (b.Build (proj), "Second Build should have succeeded.");
Assert.IsTrue (
b.Output.IsTargetSkipped ("_CompileJava"),
"the _CompileJava target should be skipped");
Expand All @@ -244,9 +218,9 @@ public void BuildAotApplicationAndÜmläüts (string supportedAbis, bool enableL
[Test]
[TestCaseSource (nameof (AotChecks))]
[Category ("Minor"), Category ("MkBundle")]
public void BuildAotApplicationAndBundleAndÜmläüts (string supportedAbis, bool enableLLVM, bool expectedResult, bool usesAssemblyBlobs)
public void BuildAotApplicationAndBundleAndÜmläüts (string supportedAbis, bool enableLLVM, bool usesAssemblyBlobs)
{
var path = Path.Combine ("temp", string.Format ("BuildAotApplicationAndBundle AndÜmläüts_{0}_{1}_{2}_{3}", supportedAbis, enableLLVM, expectedResult, usesAssemblyBlobs));
var path = Path.Combine ("temp", string.Format ("BuildAotApplicationAndBundle AndÜmläüts_{0}_{1}_{2}", supportedAbis, enableLLVM, usesAssemblyBlobs));
var proj = new XamarinAndroidApplicationProject () {
IsRelease = true,
BundleAssemblies = true,
Expand All @@ -264,9 +238,7 @@ public void BuildAotApplicationAndBundleAndÜmläüts (string supportedAbis, boo
if (!b.GetSupportedRuntimes ().Any (x => supportedAbis == x.Abi))
Assert.Ignore ($"Runtime for {supportedAbis} was not available.");
b.ThrowOnBuildFailure = false;
Assert.AreEqual (expectedResult, b.Build (proj), "Build should have {0}.", expectedResult ? "succeeded" : "failed");
if (!expectedResult)
return;
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
foreach (var abi in supportedAbis.Split (new char [] { ';' })) {
var libapp = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath,
"bundles", abi, "libmonodroid_bundle_app.so");
Expand All @@ -284,7 +256,7 @@ public void BuildAotApplicationAndBundleAndÜmläüts (string supportedAbis, boo
$"lib/{0}/libaot-UnnamedProject.dll.so should be in the {proj.PackageName}-Signed.apk", abi);
}
}
Assert.AreEqual (expectedResult, b.Build (proj), "Second Build should have {0}.", expectedResult ? "succeeded" : "failed");
Assert.IsTrue (b.Build (proj), "Second Build should have succeeded");
Assert.IsTrue (
b.Output.IsTargetSkipped ("_CompileJava"),
"the _CompileJava target should be skipped");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ public void XA5104AndroidNdkNotFound (string androidNdkDirectory)
IntermediateAssemblyDir = path
};

Assert.IsFalse (task2.Execute (), "Task should fail!");
BuildErrorEventArgs error2 = errors [1];
Assert.AreEqual (error1.Message, error2.Message, "Aot and MakeBundleNativeCodeExternal should produce the same error messages.");
Assert.IsTrue (task2.Execute (), "Aot task should succeed with no NDK!");
}
}
}

0 comments on commit dbe508e

Please sign in to comment.