From 26590d02389cbf55197240c0af224a11cb85648d Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 18 Nov 2022 15:06:56 +0100 Subject: [PATCH 1/2] [Build] Log better errors when compiling/linking with binutils If an error happens when compiling or linking native assembler files generated by Xamarin.Android, we log an error which doesn't contain much information: Error XA3006 Could not compile native assembly file: compressed_assemblies.x86.ll The real cause of the issue is logged as well, however not as an error but rather a "plain" message, which is not immediately accessible to the user experiencing the issue. Keep logging the output messages of the assembler and linker programs as before, but whenever an error occurs, log their entire output (both stdout and stderr) as an MSBuild error message. --- .../Tasks/CompileNativeAssembly.cs | 27 ++++++++++++++++--- .../Tasks/LinkApplicationSharedLibraries.cs | 27 ++++++++++++++++--- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs index 7a9780768bd..3b105a240ff 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs @@ -58,18 +58,24 @@ void RunAssembler (Config config) string assemblerName = Path.GetFileName (config.AssemblerPath); LogDebugMessage ($"[LLVM llc] {psi.FileName} {psi.Arguments}"); + + var stdoutLines = new List (); + var stderrLines = new List (); + using (var proc = new Process ()) { proc.OutputDataReceived += (s, e) => { - if (e.Data != null) + if (e.Data != null) { OnOutputData (assemblerName, s, e); - else + stdoutLines.Add (e.Data); + } else stdout_completed.Set (); }; proc.ErrorDataReceived += (s, e) => { - if (e.Data != null) + if (e.Data != null) { OnErrorData (assemblerName, s, e); - else + stderrLines.Add (e.Data); + } else stderr_completed.Set (); }; @@ -88,9 +94,22 @@ void RunAssembler (Config config) if (proc.ExitCode != 0) { LogCodedError ("XA3006", Properties.Resources.XA3006, Path.GetFileName (config.InputSource)); + LogErrors ("stdout", stdoutLines); + LogErrors ("stderr", stderrLines); Cancel (); } } + + void LogErrors (string prefix, List lines) + { + if (lines.Count == 0) { + return; + } + + foreach (string line in lines) { + Log.LogError ($"{prefix} | {line}"); + } + } } IEnumerable GetAssemblerConfigs () diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs index 0810ba6f0de..2b2c5c9b6fd 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs @@ -67,18 +67,24 @@ void RunLinker (Config config) string linkerName = Path.GetFileName (config.LinkerPath); LogDebugMessage ($"[Native Linker] {psi.FileName} {psi.Arguments}"); + + var stdoutLines = new List (); + var stderrLines = new List (); + using (var proc = new Process ()) { proc.OutputDataReceived += (s, e) => { - if (e.Data != null) + if (e.Data != null) { OnOutputData (linkerName, s, e); - else + stdoutLines.Add (e.Data); + } else stdout_completed.Set (); }; proc.ErrorDataReceived += (s, e) => { - if (e.Data != null) + if (e.Data != null) { OnErrorData (linkerName, s, e); - else + stderrLines.Add (e.Data); + } else stderr_completed.Set (); }; @@ -97,9 +103,22 @@ void RunLinker (Config config) if (proc.ExitCode != 0) { LogCodedError ("XA3007", Properties.Resources.XA3007, Path.GetFileName (config.OutputSharedLibrary)); + LogErrors ("stdout", stdoutLines); + LogErrors ("stderr", stderrLines); Cancel (); } } + + void LogErrors (string prefix, List lines) + { + if (lines.Count == 0) { + return; + } + + foreach (string line in lines) { + Log.LogError ($"{prefix} | {line}"); + } + } } IEnumerable GetLinkerConfigs () From e2d614d06c5eef3f02b550caa6e536817a3ddc15 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 18 Nov 2022 16:40:37 +0100 Subject: [PATCH 2/2] Log stdout/stderr together with the coded error --- .../Properties/Resources.resx | 9 +++---- .../Tasks/CompileNativeAssembly.cs | 16 ++----------- .../Tasks/LinkApplicationSharedLibraries.cs | 17 +++---------- .../Utilities/MonoAndroidHelper.cs | 24 +++++++++++++++++++ 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx index 55e9040f419..0edc1651fc5 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx @@ -530,11 +530,12 @@ In this message, the term "binding" means a piece of generated code that makes i "r10d" is the version of the NDK. - Could not compile native assembly file: {0} - In this message, the term "assembly" means the low-level language that an assembler like `as` takes as input. (This is different from most of the other messages, where the term "assembly" means the file type that the C# compiler produces.) + Could not compile native assembly file: {0}{1} + In this message, the term "assembly" means the low-level language that an assembler like `as` takes as input. (This is different from most of the other messages, where the term "assembly" means the file type that the C# compiler produces). The '{1}' placeholder is replaced with full output of the failed command, starting and ending with a newline. - Could not link native shared library: {0} + Could not link native shared library: {0}{1} + The '{1}' placeholder is replaced with full output of the failed command, starting and ending with a newline. Failed to generate Java type for class: {0} due to {1} @@ -886,4 +887,4 @@ In this message, the term "handheld app" means "app for handheld devices." {1} - A Filename. - \ No newline at end of file + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs index 3b105a240ff..2dca284c933 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CompileNativeAssembly.cs @@ -93,23 +93,11 @@ void RunAssembler (Config config) stdout_completed.WaitOne (TimeSpan.FromSeconds (30)); if (proc.ExitCode != 0) { - LogCodedError ("XA3006", Properties.Resources.XA3006, Path.GetFileName (config.InputSource)); - LogErrors ("stdout", stdoutLines); - LogErrors ("stderr", stderrLines); + var sb = MonoAndroidHelper.MergeStdoutAndStderrMessages (stdoutLines, stderrLines); + LogCodedError ("XA3006", Properties.Resources.XA3006, Path.GetFileName (config.InputSource), sb.ToString ()); Cancel (); } } - - void LogErrors (string prefix, List lines) - { - if (lines.Count == 0) { - return; - } - - foreach (string line in lines) { - Log.LogError ($"{prefix} | {line}"); - } - } } IEnumerable GetAssemblerConfigs () diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs index 2b2c5c9b6fd..bbe49073e8c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Text; using System.Threading; using Microsoft.Build.Framework; @@ -102,23 +103,11 @@ void RunLinker (Config config) stdout_completed.WaitOne (TimeSpan.FromSeconds (30)); if (proc.ExitCode != 0) { - LogCodedError ("XA3007", Properties.Resources.XA3007, Path.GetFileName (config.OutputSharedLibrary)); - LogErrors ("stdout", stdoutLines); - LogErrors ("stderr", stderrLines); + var sb = MonoAndroidHelper.MergeStdoutAndStderrMessages (stdoutLines, stderrLines); + LogCodedError ("XA3007", Properties.Resources.XA3007, Path.GetFileName (config.OutputSharedLibrary), sb.ToString ()); Cancel (); } } - - void LogErrors (string prefix, List lines) - { - if (lines.Count == 0) { - return; - } - - foreach (string line in lines) { - Log.LogError ($"{prefix} | {line}"); - } - } } IEnumerable GetLinkerConfigs () diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs index 73485dffb91..5e41b62be37 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs @@ -27,6 +27,30 @@ public partial class MonoAndroidHelper public static AndroidVersions SupportedVersions; public static AndroidSdkInfo AndroidSdk; + public static StringBuilder MergeStdoutAndStderrMessages (List stdout, List stderr) + { + var sb = new StringBuilder (); + + sb.AppendLine (); + AppendLines ("stdout", stdout, sb); + sb.AppendLine (); + AppendLines ("stderr", stderr, sb); + sb.AppendLine (); + + return sb; + + void AppendLines (string prefix, List lines, StringBuilder sb) + { + if (lines == null || lines.Count == 0) { + return; + } + + foreach (string line in lines) { + sb.AppendLine ($"{prefix} | {line}"); + } + } + } + public static int RunProcess (string name, string args, DataReceivedEventHandler onOutput, DataReceivedEventHandler onError, Dictionary environmentVariables = null) { var psi = new ProcessStartInfo (name, args) {