From b53a5d8bbf449acacd49cb9af65a3a170eedc3ff Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Tue, 14 Aug 2018 11:47:54 +0100 Subject: [PATCH] [Xamarin.Android.Build.Tasks] Use a Response file for AOT Fixes https://devdiv.visualstudio.com/DevDiv/_workitems/edit/609244 Windows has a limit on the length of command line arguments. As a result AOT can fail on windows if the project paths are too long. mono 2018-06 introduced a `--response=FILE` which allows us to provide all the options in a file rather than on the command line directly. --- src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs | 94 +++++++++++--------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs index 50b3209511f..dafca52074b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs @@ -447,50 +447,58 @@ bool RunAotCompiler (string assembliesPath, string aotCompiler, string aotOption { var stdout_completed = new ManualResetEvent (false); var stderr_completed = new ManualResetEvent (false); - var psi = new ProcessStartInfo () { - FileName = aotCompiler, - Arguments = aotOptions + " " + assembly, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow=true, - WindowStyle=ProcessWindowStyle.Hidden, - WorkingDirectory = WorkingDirectory, - }; - - // we do not want options to be provided out of band to the cross compilers - psi.EnvironmentVariables ["MONO_ENV_OPTIONS"] = String.Empty; - // the C code cannot parse all the license details, including the activation code that tell us which license level is allowed - // so we provide this out-of-band to the cross-compilers - this can be extended to communicate a few others bits as well - psi.EnvironmentVariables ["MONO_PATH"] = assembliesPath; - - LogDebugMessage ("[AOT] MONO_PATH=\"{0}\" MONO_ENV_OPTIONS=\"{1}\" {2} {3}", - psi.EnvironmentVariables ["MONO_PATH"], psi.EnvironmentVariables ["MONO_ENV_OPTIONS"], psi.FileName, psi.Arguments); - - using (var proc = new Process ()) { - proc.OutputDataReceived += (s, e) => { - if (e.Data != null) - OnAotOutputData (s, e); - else - stdout_completed.Set (); - }; - proc.ErrorDataReceived += (s, e) => { - if (e.Data != null) - OnAotErrorData (s, e); - else - stderr_completed.Set (); + var responseFile = Path.GetTempFileName (); + try { + File.WriteAllText (responseFile, aotOptions + " " + assembly); + + var psi = new ProcessStartInfo () { + FileName = aotCompiler, + Arguments = $"--response=\"{responseFile}\"", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + WorkingDirectory = WorkingDirectory, }; - proc.StartInfo = psi; - proc.Start (); - proc.BeginOutputReadLine (); - proc.BeginErrorReadLine (); - token.Register (() => { try { proc.Kill (); } catch (Exception) { } }); - proc.WaitForExit (); - if (psi.RedirectStandardError) - stderr_completed.WaitOne (TimeSpan.FromSeconds (30)); - if (psi.RedirectStandardOutput) - stdout_completed.WaitOne (TimeSpan.FromSeconds (30)); - return proc.ExitCode == 0; + + // we do not want options to be provided out of band to the cross compilers + psi.EnvironmentVariables ["MONO_ENV_OPTIONS"] = String.Empty; + // the C code cannot parse all the license details, including the activation code that tell us which license level is allowed + // so we provide this out-of-band to the cross-compilers - this can be extended to communicate a few others bits as well + psi.EnvironmentVariables ["MONO_PATH"] = assembliesPath; + + LogDebugMessage ("[AOT] MONO_PATH=\"{0}\" MONO_ENV_OPTIONS=\"{1}\" {2} {3}", + psi.EnvironmentVariables ["MONO_PATH"], psi.EnvironmentVariables ["MONO_ENV_OPTIONS"], psi.FileName, psi.Arguments); + + using (var proc = new Process ()) { + proc.OutputDataReceived += (s, e) => { + if (e.Data != null) + OnAotOutputData (s, e); + else + stdout_completed.Set (); + }; + proc.ErrorDataReceived += (s, e) => { + if (e.Data != null) + OnAotErrorData (s, e); + else + stderr_completed.Set (); + }; + proc.StartInfo = psi; + proc.Start (); + proc.BeginOutputReadLine (); + proc.BeginErrorReadLine (); + token.Register (() => { try { proc.Kill (); } catch (Exception) { } }); + proc.WaitForExit (); + if (psi.RedirectStandardError) + stderr_completed.WaitOne (TimeSpan.FromSeconds (30)); + if (psi.RedirectStandardOutput) + stdout_completed.WaitOne (TimeSpan.FromSeconds (30)); + return proc.ExitCode == 0; + } + } finally { + if (File.Exists (responseFile)) + File.Delete (responseFile); } }