Skip to content

Commit 949cf56

Browse files
committed
[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.
1 parent 08c986e commit 949cf56

File tree

2 files changed

+64
-64
lines changed

2 files changed

+64
-64
lines changed

src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs

Lines changed: 63 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,6 @@ static string GetNdkToolchainLibraryDir (string binDir, AndroidTargetArch arch)
166166
return GetNdkToolchainLibraryDir (binDir, NdkUtil.GetArchDirName (arch));
167167
}
168168

169-
static string GetShortPath (string path)
170-
{
171-
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
172-
return QuoteFileName (path);
173-
var shortPath = KernelEx.GetShortPathName (Path.GetDirectoryName (path));
174-
return Path.Combine (shortPath, Path.GetFileName (path));
175-
}
176-
177169
static string QuoteFileName(string fileName)
178170
{
179171
var builder = new CommandLineBuilder();
@@ -385,7 +377,6 @@ IEnumerable<Config> GetAotConfigs ()
385377
} catch (InvalidOperationException ex) {
386378
Diagnostic.Error (5101, ex.Message);
387379
}
388-
389380
string toolchainLibDir;
390381
if (NdkUtil.UsingClangNDK)
391382
toolchainLibDir = GetNdkToolchainLibraryDir (toolchainPath, arch);
@@ -394,19 +385,19 @@ IEnumerable<Config> GetAotConfigs ()
394385

395386
var libs = new List<string>();
396387
if (NdkUtil.UsingClangNDK) {
397-
libs.Add ($"-L{GetShortPath (toolchainLibDir)}");
398-
libs.Add ($"-L{GetShortPath (androidLibPath)}");
388+
libs.Add ($"-L{toolchainLibDir}");
389+
libs.Add ($"-L{androidLibPath}");
399390

400391
if (arch == AndroidTargetArch.Arm) {
401392
// Needed for -lunwind to work
402393
string compilerLibDir = Path.Combine (toolchainPath, "..", "sysroot", "usr", "lib", NdkUtil.GetArchDirName (arch));
403-
libs.Add ($"-L{GetShortPath (compilerLibDir)}");
394+
libs.Add ($"-L{compilerLibDir}");
404395
}
405396
}
406397

407-
libs.Add (GetShortPath (Path.Combine (toolchainLibDir, "libgcc.a")));
408-
libs.Add (GetShortPath (Path.Combine (androidLibPath, "libc.so")));
409-
libs.Add (GetShortPath (Path.Combine (androidLibPath, "libm.so")));
398+
libs.Add (Path.Combine (toolchainLibDir, "libgcc.a"));
399+
libs.Add (Path.Combine (androidLibPath, "libc.so"));
400+
libs.Add (Path.Combine (androidLibPath, "libm.so"));
410401

411402
ldFlags = string.Join(";", libs);
412403
}
@@ -427,17 +418,17 @@ IEnumerable<Config> GetAotConfigs ()
427418
if (!string.IsNullOrEmpty (AotAdditionalArguments))
428419
aotOptions.Add (AotAdditionalArguments);
429420
if (sequencePointsMode == SequencePointsMode.Offline)
430-
aotOptions.Add ("msym-dir=" + GetShortPath (outdir));
421+
aotOptions.Add ("msym-dir=" + QuoteFileName (outdir));
431422
if (AotMode != AotMode.Normal)
432423
aotOptions.Add (AotMode.ToString ().ToLowerInvariant ());
433424

434-
aotOptions.Add ("outfile=" + GetShortPath (outputFile));
425+
aotOptions.Add ("outfile=" + QuoteFileName (outputFile));
435426
aotOptions.Add ("asmwriter");
436427
aotOptions.Add ("mtriple=" + mtriple);
437-
aotOptions.Add ("tool-prefix=" + GetShortPath (toolPrefix));
428+
aotOptions.Add ("tool-prefix=" + QuoteFileName (toolPrefix));
438429
aotOptions.Add ("ld-flags=" + ldFlags);
439-
aotOptions.Add ("llvm-path=" + GetShortPath (sdkBinDirectory));
440-
aotOptions.Add ("temp-path=" + GetShortPath (tempDir));
430+
aotOptions.Add ("llvm-path=" + QuoteFileName (sdkBinDirectory));
431+
aotOptions.Add ("temp-path=" + QuoteFileName (tempDir));
441432

442433
string aotOptionsStr = (EnableLLVM ? "--llvm " : "") + "--aot=" + string.Join (",", aotOptions);
443434

@@ -470,50 +461,59 @@ bool RunAotCompiler (string assembliesPath, string aotCompiler, string aotOption
470461
{
471462
var stdout_completed = new ManualResetEvent (false);
472463
var stderr_completed = new ManualResetEvent (false);
473-
var psi = new ProcessStartInfo () {
474-
FileName = aotCompiler,
475-
Arguments = aotOptions + " " + assembly,
476-
UseShellExecute = false,
477-
RedirectStandardOutput = true,
478-
RedirectStandardError = true,
479-
CreateNoWindow=true,
480-
WindowStyle=ProcessWindowStyle.Hidden,
481-
WorkingDirectory = WorkingDirectory,
482-
};
483-
484-
// we do not want options to be provided out of band to the cross compilers
485-
psi.EnvironmentVariables ["MONO_ENV_OPTIONS"] = String.Empty;
486-
// the C code cannot parse all the license details, including the activation code that tell us which license level is allowed
487-
// so we provide this out-of-band to the cross-compilers - this can be extended to communicate a few others bits as well
488-
psi.EnvironmentVariables ["MONO_PATH"] = assembliesPath;
489-
490-
LogDebugMessage ("[AOT] MONO_PATH=\"{0}\" MONO_ENV_OPTIONS=\"{1}\" {2} {3}",
491-
psi.EnvironmentVariables ["MONO_PATH"], psi.EnvironmentVariables ["MONO_ENV_OPTIONS"], psi.FileName, psi.Arguments);
492-
493-
using (var proc = new Process ()) {
494-
proc.OutputDataReceived += (s, e) => {
495-
if (e.Data != null)
496-
OnAotOutputData (s, e);
497-
else
498-
stdout_completed.Set ();
499-
};
500-
proc.ErrorDataReceived += (s, e) => {
501-
if (e.Data != null)
502-
OnAotErrorData (s, e);
503-
else
504-
stderr_completed.Set ();
464+
var responseFile = Path.GetTempFileName ();
465+
try {
466+
File.WriteAllText (responseFile, aotOptions + " " + assembly);
467+
468+
var psi = new ProcessStartInfo () {
469+
FileName = aotCompiler,
470+
Arguments = $"--response=\"{responseFile}\"",
471+
UseShellExecute = false,
472+
RedirectStandardOutput = true,
473+
RedirectStandardError = true,
474+
CreateNoWindow = true,
475+
WindowStyle = ProcessWindowStyle.Hidden,
476+
WorkingDirectory = WorkingDirectory,
505477
};
506-
proc.StartInfo = psi;
507-
proc.Start ();
508-
proc.BeginOutputReadLine ();
509-
proc.BeginErrorReadLine ();
510-
Token.Register (() => { try { proc.Kill (); } catch (Exception) { } });
511-
proc.WaitForExit ();
512-
if (psi.RedirectStandardError)
513-
stderr_completed.WaitOne (TimeSpan.FromSeconds (30));
514-
if (psi.RedirectStandardOutput)
515-
stdout_completed.WaitOne (TimeSpan.FromSeconds (30));
516-
return proc.ExitCode == 0;
478+
479+
// we do not want options to be provided out of band to the cross compilers
480+
psi.EnvironmentVariables ["MONO_ENV_OPTIONS"] = String.Empty;
481+
// the C code cannot parse all the license details, including the activation code that tell us which license level is allowed
482+
// so we provide this out-of-band to the cross-compilers - this can be extended to communicate a few others bits as well
483+
psi.EnvironmentVariables ["MONO_PATH"] = assembliesPath;
484+
485+
LogDebugMessage ($"[AOT] {aotOptions} {assembly}");
486+
LogDebugMessage ("[AOT] MONO_PATH=\"{0}\" MONO_ENV_OPTIONS=\"{1}\" {2} {3}",
487+
psi.EnvironmentVariables ["MONO_PATH"], psi.EnvironmentVariables ["MONO_ENV_OPTIONS"], psi.FileName, psi.Arguments);
488+
489+
using (var proc = new Process ()) {
490+
proc.OutputDataReceived += (s, e) => {
491+
if (e.Data != null)
492+
OnAotOutputData (s, e);
493+
else
494+
stdout_completed.Set ();
495+
};
496+
proc.ErrorDataReceived += (s, e) => {
497+
if (e.Data != null)
498+
OnAotErrorData (s, e);
499+
else
500+
stderr_completed.Set ();
501+
};
502+
proc.StartInfo = psi;
503+
proc.Start ();
504+
proc.BeginOutputReadLine ();
505+
proc.BeginErrorReadLine ();
506+
Token.Register (() => { try { proc.Kill (); } catch (Exception) { } });
507+
proc.WaitForExit ();
508+
if (psi.RedirectStandardError)
509+
stderr_completed.WaitOne (TimeSpan.FromSeconds (30));
510+
if (psi.RedirectStandardOutput)
511+
stdout_completed.WaitOne (TimeSpan.FromSeconds (30));
512+
return proc.ExitCode == 0;
513+
}
514+
} finally {
515+
if (File.Exists (responseFile))
516+
File.Delete (responseFile);
517517
}
518518
}
519519

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ public void BuildAotApplication (string supportedAbis, bool enableLLVM, bool exp
673673
// LLVM passes a direct path to libc.so, and we need to use the libc.so
674674
// which corresponds to the *minimum* SDK version specified in AndroidManifest.xml
675675
// Since we overrode minSdkVersion=16, that means we should use libc.so from android-16.
676-
var rightLibc = new Regex (@"^\s*\[AOT\].*cross-.*--llvm.*,ld-flags=.*android-16.arch-.*.usr.lib.libc\.so", RegexOptions.Multiline);
676+
var rightLibc = new Regex (@"\s*\[aot-compiler stdout].*android-16.arch-.*.usr.lib.libc\.so", RegexOptions.Multiline);
677677
var m = rightLibc.Match (string.Join ("\n",b.LastBuildOutput));
678678
Assert.IsTrue (m.Success, "AOT+LLVM should use libc.so from minSdkVersion!");
679679
}

0 commit comments

Comments
 (0)