Skip to content

Commit b2f0441

Browse files
[MonoAOTCompiler] more properties & custom WorkingDirectory (#62725)
Fixes: #56163 PR #58523 fixed something on Windows, but it didn't actually address our issues on Android. A directory name like `foo Ümläüts` fails: * `mkdir 'foo Ümläüts' ; cd 'foo Ümläüts'` * `dotnet new android` * `dotnet build -c Release -p:RunAOTCompilation=true` (adding `-p:EnableLLVM=true` complicates further) The error: Precompiling failed for C:\src\foo Ümläüts\obj\Release\android-arm64\linked\System.Private.CoreLib.dll: Error: Loaded assembly 'C:\src\foo ├£ml├ñ├╝ts\obj\Release\android-arm64\linked\System.Private.CoreLib.dll' doesn't match original file name 'C:\foo ▄mlΣⁿts\obj\Release\android-arm64\linked\System.Private.CoreLib.dll'. Set MONO_PATH to the assembly's location. Reviewing the existing AOT implementation in Xamarin.Android, I found out *why* Xamarin.Android works: [AOT] response file obj\Release\120\aot\arm64-v8a\App36.dll\response.txt: --llvm "--aot=temp-path=obj\Release\120\aot\arm64-v8a\App36.dll,llvm-path=C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Xamarin\Android,outfile=obj\Release\120\aot\arm64-v8a\libaot-App36.dll.so,msym-dir=obj\Release\120\aot\arm64-v8a,asmwriter,mtriple=aarch64-linux-android,tool-prefix=C:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\aarch64-linux-android-,ld-name=ld.EXE,ld-flags=\"-LC:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\lib\gcc\aarch64-linux-android\4.9.x\";\"-LC:\Program Files (x86)\Android\android-sdk\ndk-bundle\platforms\android-21\arch-arm64\usr\lib\";\"C:\Program Files (x86)\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\lib\gcc\aarch64-linux-android\4.9.x\libgcc.a\";\"C:\Program Files (x86)\Android\android-sdk\ndk-bundle\platforms\android-21\arch-arm64\usr\lib\libc.so\";\"C:\Program Files (x86)\Android\android-sdk\ndk-bundle\platforms\android-21\arch-arm64\usr\lib\libm.so\"" C:\Users\jopepper\source\repos\App36\App36\obj\Release\120\android\assets\shrunk\App36.dll 1. Xamarin.Android passes *relative* paths. The `foo Ümläüts` directory name doesn't even come into play for some arguments. 2. With LLVM, `ld-flags` contains a `;`. The existing code splits on `;` and joins on `,`: https://github.com/dotnet/runtime/blob/25c207351c4f57cf2daa98caaf327a8b8d83edb8/src/tasks/AotCompilerTask/MonoAOTCompiler.cs#L505-L509 So we lose any `;` delimiters for the `ld-flags` value, they get replaced by `,`. I think the solution here is: 1. Add several missing properties to `<MonoAOTCompiler/>` so we don't have to rely on the `%(AotArguments)` item metadata. No splitting on `;` would be required, `ld-flags` can be passed in and used as-is. 2. Add a new `WorkingDirectory` property. When this is set, assume paths passed in might be relative -- and don't transform paths by calling `Path.GetFullPath()`. Lastly, I fixed a place where the UTF8 encoding wasn't passed when MSBuild logging the response file. These changes I tried to make in a way where this shouldn't break other .NET workloads like wasm. If existing MSBuild targets call this task (not using the new properties), the behavior should remain unchanged. I tested these changes by commiting a modified `MonoAOTCompiler.dll`: dotnet/android#6562 I'm able to enable several AOT tests related to #56163.
1 parent 4733c70 commit b2f0441

File tree

1 file changed

+63
-5
lines changed

1 file changed

+63
-5
lines changed

src/tasks/AotCompilerTask/MonoAOTCompiler.cs

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,39 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
191191
/// </summary>
192192
public string? CacheFilePath { get; set; }
193193

194+
/// <summary>
195+
/// Passes additional, custom arguments to --aot
196+
/// </summary>
197+
public string? AotArguments { get; set; }
198+
199+
/// <summary>
200+
/// Passes temp-path to the AOT compiler
201+
/// </summary>
202+
public string? TempPath { get; set; }
203+
204+
/// <summary>
205+
/// Passes ld-name to the AOT compiler, for use with UseLLVM=true
206+
/// </summary>
207+
public string? LdName { get; set; }
208+
209+
/// <summary>
210+
/// Passes ld-flags to the AOT compiler, for use with UseLLVM=true
211+
/// </summary>
212+
public string? LdFlags { get; set; }
213+
214+
/// <summary>
215+
/// Specify WorkingDirectory for the AOT compiler
216+
/// </summary>
217+
public string? WorkingDirectory { get; set; }
218+
194219
[Required]
195220
public string IntermediateOutputPath { get; set; } = string.Empty;
196221

197222
[Output]
198223
public string[]? FileWrites { get; private set; }
199224

225+
private static readonly Encoding s_utf8Encoding = new UTF8Encoding(false);
226+
200227
private List<string> _fileWrites = new();
201228

202229
private IList<ITaskItem>? _assembliesToCompile;
@@ -225,7 +252,9 @@ private bool ProcessAndValidateArguments()
225252
return false;
226253
}
227254

228-
if (!Path.IsPathRooted(OutputDir))
255+
// A relative path might be used along with WorkingDirectory,
256+
// only call Path.GetFullPath() if WorkingDirectory is blank.
257+
if (string.IsNullOrEmpty(WorkingDirectory) && !Path.IsPathRooted(OutputDir))
229258
OutputDir = Path.GetFullPath(OutputDir);
230259

231260
if (!Directory.Exists(OutputDir))
@@ -682,6 +711,26 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st
682711
}
683712
}
684713

714+
if (!string.IsNullOrEmpty(AotArguments))
715+
{
716+
aotArgs.Add(AotArguments);
717+
}
718+
719+
if (!string.IsNullOrEmpty(TempPath))
720+
{
721+
aotArgs.Add($"temp-path={TempPath}");
722+
}
723+
724+
if (!string.IsNullOrEmpty(LdName))
725+
{
726+
aotArgs.Add($"ld-name={LdName}");
727+
}
728+
729+
if (!string.IsNullOrEmpty(LdFlags))
730+
{
731+
aotArgs.Add($"ld-flags={LdFlags}");
732+
}
733+
685734
// we need to quote the entire --aot arguments here to make sure it is parsed
686735
// on Windows as one argument. Otherwise it will be split up into multiple
687736
// values, which wont work.
@@ -694,7 +743,16 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st
694743
}
695744
else
696745
{
697-
processArgs.Add('"' + assemblyFilename + '"');
746+
if (string.IsNullOrEmpty(WorkingDirectory))
747+
{
748+
processArgs.Add('"' + assemblyFilename + '"');
749+
}
750+
else
751+
{
752+
// If WorkingDirectory is supplied, the caller could be passing in a relative path
753+
// Use the original ItemSpec that was passed in.
754+
processArgs.Add('"' + assemblyItem.ItemSpec + '"');
755+
}
698756
}
699757

700758
monoPaths = $"{assemblyDir}{Path.PathSeparator}{monoPaths}";
@@ -706,14 +764,14 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st
706764

707765
var responseFileContent = string.Join(" ", processArgs);
708766
var responseFilePath = Path.GetTempFileName();
709-
using (var sw = new StreamWriter(responseFilePath, append: false, encoding: new UTF8Encoding(false)))
767+
using (var sw = new StreamWriter(responseFilePath, append: false, encoding: s_utf8Encoding))
710768
{
711769
sw.WriteLine(responseFileContent);
712770
}
713771

714772
return new PrecompileArguments(ResponseFilePath: responseFilePath,
715773
EnvironmentVariables: envVariables,
716-
WorkingDir: assemblyDir,
774+
WorkingDir: string.IsNullOrEmpty(WorkingDirectory) ? assemblyDir : WorkingDirectory,
717775
AOTAssembly: aotAssembly,
718776
ProxyFiles: proxyFiles);
719777
}
@@ -741,7 +799,7 @@ private bool PrecompileLibrary(PrecompileArguments args)
741799
StringBuilder envStr = new StringBuilder(string.Empty);
742800
foreach (KeyValuePair<string, string> kvp in args.EnvironmentVariables)
743801
envStr.Append($"{kvp.Key}={kvp.Value} ");
744-
Log.LogMessage(importance, $"{msgPrefix}Exec (with response file contents expanded) in {args.WorkingDir}: {envStr}{CompilerBinaryPath} {File.ReadAllText(args.ResponseFilePath)}");
802+
Log.LogMessage(importance, $"{msgPrefix}Exec (with response file contents expanded) in {args.WorkingDir}: {envStr}{CompilerBinaryPath} {File.ReadAllText(args.ResponseFilePath, s_utf8Encoding)}");
745803
}
746804

747805
if (exitCode != 0)

0 commit comments

Comments
 (0)