Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/tasks
diff options
context:
space:
mode:
authorAlexander Köplinger <alex.koeplinger@outlook.com>2021-07-15 23:40:54 +0300
committerGitHub <noreply@github.com>2021-07-15 23:40:54 +0300
commitbd416d7bca63c0411547750a050aa57a902ba2ff (patch)
tree3a76f977834cfe59e0ff352c4a70ffd9e0b15552 /src/tasks
parent19b1b486258d5f3ff498919670b8e68f700b2819 (diff)
Add option to MonoAOTCompiler msbuild task to generate .so files (#55753)
Diffstat (limited to 'src/tasks')
-rw-r--r--src/tasks/AndroidAppBuilder/ApkBuilder.cs36
-rw-r--r--src/tasks/AndroidAppBuilder/Templates/monodroid.c5
-rw-r--r--src/tasks/AotCompilerTask/MonoAOTCompiler.cs184
-rw-r--r--src/tasks/AotCompilerTask/MonoAOTCompiler.props2
4 files changed, 195 insertions, 32 deletions
diff --git a/src/tasks/AndroidAppBuilder/ApkBuilder.cs b/src/tasks/AndroidAppBuilder/ApkBuilder.cs
index b979ba316b3..23475c9e1e6 100644
--- a/src/tasks/AndroidAppBuilder/ApkBuilder.cs
+++ b/src/tasks/AndroidAppBuilder/ApkBuilder.cs
@@ -125,11 +125,13 @@ public class ApkBuilder
var assemblerFiles = new StringBuilder();
var assemblerFilesToLink = new StringBuilder();
+ var aotLibraryFiles = new List<string>();
foreach (ITaskItem file in Assemblies)
{
// use AOT files if available
var obj = file.GetMetadata("AssemblerFile");
var llvmObj = file.GetMetadata("LlvmObjectFile");
+ var lib = file.GetMetadata("LibraryFile");
if (!string.IsNullOrEmpty(obj))
{
@@ -143,9 +145,14 @@ public class ApkBuilder
var name = Path.GetFileNameWithoutExtension(llvmObj);
assemblerFilesToLink.AppendLine($" {llvmObj}");
}
+
+ if (!string.IsNullOrEmpty(lib))
+ {
+ aotLibraryFiles.Add(lib);
+ }
}
- if (ForceAOT && assemblerFiles.Length == 0)
+ if (ForceAOT && assemblerFiles.Length == 0 && aotLibraryFiles.Count == 0)
{
throw new InvalidOperationException("Need list of AOT files.");
}
@@ -165,7 +172,8 @@ public class ApkBuilder
// Copy sourceDir to OutputDir/assets-tozip (ignore native files)
// these files then will be zipped and copied to apk/assets/assets.zip
- Utils.DirectoryCopy(AppDir, Path.Combine(OutputDir, "assets-tozip"), file =>
+ var assetsToZipDirectory = Path.Combine(OutputDir, "assets-tozip");
+ Utils.DirectoryCopy(AppDir, assetsToZipDirectory, file =>
{
string fileName = Path.GetFileName(file);
string extension = Path.GetExtension(file);
@@ -184,6 +192,12 @@ public class ApkBuilder
return true;
});
+ // add AOT .so libraries
+ foreach (var aotlib in aotLibraryFiles)
+ {
+ File.Copy(aotlib, Path.Combine(assetsToZipDirectory, Path.GetFileName(aotlib)));
+ }
+
// tools:
string dx = Path.Combine(buildToolsFolder, "dx");
string aapt = Path.Combine(buildToolsFolder, "aapt");
@@ -195,8 +209,8 @@ public class ApkBuilder
string cmake = "cmake";
string zip = "zip";
- Utils.RunProcess(zip, workingDir: Path.Combine(OutputDir, "assets-tozip"), args: "-q -r ../assets/assets.zip .");
- Directory.Delete(Path.Combine(OutputDir, "assets-tozip"), true);
+ Utils.RunProcess(zip, workingDir: assetsToZipDirectory, args: "-q -r ../assets/assets.zip .");
+ Directory.Delete(assetsToZipDirectory, true);
if (!File.Exists(androidJar))
throw new ArgumentException($"API level={BuildApiLevel} is not downloaded in Android SDK");
@@ -283,22 +297,26 @@ public class ApkBuilder
.Replace("%AotSources%", aotSources)
.Replace("%AotModulesSource%", string.IsNullOrEmpty(aotSources) ? "" : "modules.c");
- string defines = "";
+ var defines = new StringBuilder();
if (ForceInterpreter)
{
- defines = "add_definitions(-DFORCE_INTERPRETER=1)";
+ defines.AppendLine("add_definitions(-DFORCE_INTERPRETER=1)");
}
else if (ForceAOT)
{
- defines = "add_definitions(-DFORCE_AOT=1)";
+ defines.AppendLine("add_definitions(-DFORCE_AOT=1)");
+ if (aotLibraryFiles.Count == 0)
+ {
+ defines.AppendLine("add_definitions(-DSTATIC_AOT=1)");
+ }
}
if (!string.IsNullOrEmpty(DiagnosticPorts))
{
- defines += "\nadd_definitions(-DDIAGNOSTIC_PORTS=\"" + DiagnosticPorts + "\")";
+ defines.AppendLine("add_definitions(-DDIAGNOSTIC_PORTS=\"" + DiagnosticPorts + "\")");
}
- cmakeLists = cmakeLists.Replace("%Defines%", defines);
+ cmakeLists = cmakeLists.Replace("%Defines%", defines.ToString());
File.WriteAllText(Path.Combine(OutputDir, "CMakeLists.txt"), cmakeLists);
diff --git a/src/tasks/AndroidAppBuilder/Templates/monodroid.c b/src/tasks/AndroidAppBuilder/Templates/monodroid.c
index 7bd0464075e..4ed02eb2166 100644
--- a/src/tasks/AndroidAppBuilder/Templates/monodroid.c
+++ b/src/tasks/AndroidAppBuilder/Templates/monodroid.c
@@ -191,7 +191,7 @@ log_callback (const char *log_domain, const char *log_level, const char *message
}
}
-#if FORCE_AOT
+#if defined(FORCE_AOT) && defined(STATIC_AOT)
void register_aot_modules (void);
#endif
@@ -270,7 +270,10 @@ mono_droid_runtime_init (const char* executable, int managed_argc, char* managed
LOG_INFO("Interp Enabled");
mono_jit_set_aot_mode(MONO_AOT_MODE_INTERP_ONLY);
#elif FORCE_AOT
+ LOG_INFO("AOT Enabled");
+#if STATIC_AOT
register_aot_modules();
+#endif
mono_jit_set_aot_mode(MONO_AOT_MODE_FULL);
#endif
diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
index cb3876cfc9c..259622da707 100644
--- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
+++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
@@ -49,12 +49,18 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
public string? OutputDir { get; set; }
/// <summary>
+ /// Target triple passed to the AOT compiler.
+ /// </summary>
+ public string? Triple { get; set; }
+
+ /// <summary>
/// Assemblies which were AOT compiled.
///
/// Successful AOT compilation will set the following metadata on the items:
/// - AssemblerFile (when using OutputType=AsmOnly)
/// - ObjectFile (when using OutputType=Normal)
- /// - AotDataFile
+ /// - LibraryFile (when using OutputType=Library)
+ /// - AotDataFile (when using UseAotDataFile=true)
/// - LlvmObjectFile (if using LLVM)
/// - LlvmBitcodeFile (if using LLVM-only)
/// </summary>
@@ -73,13 +79,37 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
public bool UseLLVM { get; set; }
/// <summary>
- /// Use a separate .aotdata file for the AOT data.
+ /// This instructs the AOT code generator to output certain data constructs into a separate file. This can reduce the executable images some five to twenty percent.
+ /// Developers need to then ship the resulting aotdata as a resource and register a hook to load the data on demand by using the mono_install_load_aot_data_hook() method.
/// Defaults to true.
/// </summary>
public bool UseAotDataFile { get; set; } = true;
/// <summary>
- /// File to use for profile-guided optimization.
+ /// Create an ELF object file (.o) or .s file which can be statically linked into an executable when embedding the mono runtime.
+ /// Only valid if OutputType is ObjectFile or AsmOnly.
+ /// </summary>
+ public bool UseStaticLinking { get; set; }
+
+ /// <summary>
+ /// When this option is specified, icalls (internal calls made from the standard library into the mono runtime code) are invoked directly instead of going through the operating system symbol lookup operation.
+ /// This requires UseStaticLinking=true.
+ /// </summary>
+ public bool UseDirectIcalls { get; set; }
+
+ /// <summary>
+ /// When this option is specified, P/Invoke methods are invoked directly instead of going through the operating system symbol lookup operation
+ /// This requires UseStaticLinking=true.
+ /// </summary>
+ public bool UseDirectPInvoke { get; set; }
+
+ /// <summary>
+ /// Instructs the AOT compiler to emit DWARF debugging information.
+ /// </summary>
+ public bool UseDwarfDebug { get; set; }
+
+ /// <summary>
+ /// File to use for profile-guided optimization, *only* the methods described in the file will be AOT compiled.
/// </summary>
public string? AotProfilePath { get; set; }
@@ -89,8 +119,8 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
public string[]? Profilers { get; set; }
/// <summary>
- /// Generate a file containing mono_aot_register_module() calls for each AOT module
- /// Defaults to false.
+ /// Generate a file containing mono_aot_register_module() calls for each AOT module which can be compiled into the app embedding mono.
+ /// If set, this implies UseStaticLinking=true.
/// </summary>
public string? AotModulesTablePath { get; set; }
@@ -101,7 +131,7 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
public string? AotModulesTableLanguage { get; set; } = nameof(MonoAotModulesTableLanguage.C);
/// <summary>
- /// Choose between 'Normal', 'JustInterp', 'Full', 'FullInterp', 'LLVMOnly', 'LLVMOnlyInterp'.
+ /// Choose between 'Normal', 'JustInterp', 'Full', 'FullInterp', 'Hybrid', 'LLVMOnly', 'LLVMOnlyInterp'.
/// LLVMOnly means to use only LLVM for FullAOT, AOT result will be a LLVM Bitcode file (the cross-compiler must be built with LLVM support)
/// The "interp" options ('LLVMOnlyInterp' and 'FullInterp') mean generate necessary support to fall back to interpreter if AOT code is not possible for some methods.
/// The difference between 'JustInterp' and 'FullInterp' is that 'FullInterp' will AOT all the methods in the given assemblies, while 'JustInterp' will only AOT the wrappers and trampolines necessary for the runtime to execute the managed methods using the interpreter and to interoperate with P/Invokes and unmanaged callbacks.
@@ -109,10 +139,21 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
public string Mode { get; set; } = nameof(MonoAotMode.Normal);
/// <summary>
- /// Choose between 'Normal', 'AsmOnly'
- /// AsmOnly means the AOT compiler will produce .s assembly code instead of an .o object file.
+ /// Choose between 'ObjectFile', 'AsmOnly', 'Library'
+ /// ObjectFile means the AOT compiler will produce an .o object file, AsmOnly will produce .s assembly code and Library will produce a .so/.dylib/.dll shared library.
+ /// </summary>
+ public string OutputType { get; set; } = nameof(MonoAotOutputType.ObjectFile);
+
+ /// <summary>
+ /// Choose between 'Dll', 'Dylib', 'So'. Only valid if OutputType is Library.
+ /// Dll means the AOT compiler will produce a Windows PE .dll file, Dylib means an Apple Mach-O .dylib and So means a Linux/Android ELF .so file.
+ /// </summary>
+ public string? LibraryFormat { get; set; }
+
+ /// <summary>
+ /// Prefix that will be added to the library file name, e.g. to add 'lib' prefix required by some platforms. Only valid if OutputType is Library.
/// </summary>
- public string OutputType { get; set; } = nameof(MonoAotOutputType.Normal);
+ public string LibraryFilePrefix { get; set; } = "";
/// <summary>
/// Path to the directory where LLVM binaries (opt and llc) are found.
@@ -121,6 +162,11 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
public string? LLVMPath { get; set; }
/// <summary>
+ /// Prepends a prefix to the name of tools ran by the AOT compiler, i.e. 'as'/'ld'.
+ /// </summary>
+ public string? ToolPrefix { get; set; }
+
+ /// <summary>
/// Path to the directory where msym artifacts are stored.
/// </summary>
public string? MsymPath { get; set; }
@@ -143,6 +189,7 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
private ConcurrentBag<ITaskItem> compiledAssemblies = new ConcurrentBag<ITaskItem>();
private MonoAotMode parsedAotMode;
private MonoAotOutputType parsedOutputType;
+ private MonoAotLibraryFormat parsedLibraryFormat;
private MonoAotModulesTableLanguage parsedAotModulesTableLanguage;
public override bool Execute()
@@ -200,10 +247,25 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
switch (OutputType)
{
- case "Normal": parsedOutputType = MonoAotOutputType.Normal; break;
+ case "ObjectFile": parsedOutputType = MonoAotOutputType.ObjectFile; break;
case "AsmOnly": parsedOutputType = MonoAotOutputType.AsmOnly; break;
+ case "Library": parsedOutputType = MonoAotOutputType.Library; break;
+ case "Normal":
+ Log.LogWarning($"'{nameof(OutputType)}=Normal' is deprecated, use 'ObjectFile' instead.");
+ parsedOutputType = MonoAotOutputType.ObjectFile; break;
default:
- throw new ArgumentException($"'{nameof(OutputType)}' must be one of: '{nameof(MonoAotOutputType.Normal)}', '{nameof(MonoAotOutputType.AsmOnly)}'. Received: '{OutputType}'.", nameof(OutputType));
+ throw new ArgumentException($"'{nameof(OutputType)}' must be one of: '{nameof(MonoAotOutputType.ObjectFile)}', '{nameof(MonoAotOutputType.AsmOnly)}', '{nameof(MonoAotOutputType.Library)}'. Received: '{OutputType}'.", nameof(OutputType));
+ }
+
+ switch (LibraryFormat)
+ {
+ case "Dll": parsedLibraryFormat = MonoAotLibraryFormat.Dll; break;
+ case "Dylib": parsedLibraryFormat = MonoAotLibraryFormat.Dylib; break;
+ case "So": parsedLibraryFormat = MonoAotLibraryFormat.So; break;
+ default:
+ if (parsedOutputType == MonoAotOutputType.Library)
+ throw new ArgumentException($"'{nameof(LibraryFormat)}' must be one of: '{nameof(MonoAotLibraryFormat.Dll)}', '{nameof(MonoAotLibraryFormat.Dylib)}', '{nameof(MonoAotLibraryFormat.So)}'. Received: '{LibraryFormat}'.", nameof(LibraryFormat));
+ break;
}
if (parsedAotMode == MonoAotMode.LLVMOnly && !UseLLVM)
@@ -219,8 +281,29 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
throw new ArgumentException($"'{nameof(AotModulesTableLanguage)}' must be one of: '{nameof(MonoAotModulesTableLanguage.C)}', '{nameof(MonoAotModulesTableLanguage.ObjC)}'. Received: '{AotModulesTableLanguage}'.", nameof(AotModulesTableLanguage));
}
- if (!string.IsNullOrEmpty(AotModulesTablePath) && !GenerateAotModulesTable(Assemblies, Profilers))
- return false;
+ if (!string.IsNullOrEmpty(AotModulesTablePath))
+ {
+ // AOT modules for static linking, needs the aot modules table
+ UseStaticLinking = true;
+
+ if (!GenerateAotModulesTable(Assemblies, Profilers))
+ return false;
+ }
+
+ if (UseDirectIcalls && !UseStaticLinking)
+ {
+ throw new ArgumentException($"'{nameof(UseDirectIcalls)}' can only be used with '{nameof(UseStaticLinking)}=true'.", nameof(UseDirectIcalls));
+ }
+
+ if (UseDirectPInvoke && !UseStaticLinking)
+ {
+ throw new ArgumentException($"'{nameof(UseDirectPInvoke)}' can only be used with '{nameof(UseStaticLinking)}=true'.", nameof(UseDirectPInvoke));
+ }
+
+ if (UseStaticLinking && (parsedOutputType == MonoAotOutputType.Library))
+ {
+ throw new ArgumentException($"'{nameof(OutputType)}=Library' can not be used with '{nameof(UseStaticLinking)}=true'.", nameof(OutputType));
+ }
string? monoPaths = null;
if (AdditionalAssemblySearchPaths != null)
@@ -287,6 +370,26 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
processArgs.Add("--nollvm");
}
+ if (UseStaticLinking)
+ {
+ aotArgs.Add($"static");
+ }
+
+ if (UseDwarfDebug)
+ {
+ aotArgs.Add($"dwarfdebug");
+ }
+
+ if (!string.IsNullOrEmpty(Triple))
+ {
+ aotArgs.Add($"mtriple={Triple}");
+ }
+
+ if (!string.IsNullOrEmpty(ToolPrefix))
+ {
+ aotArgs.Add($"tool-prefix={ToolPrefix}");
+ }
+
string assemblyFilename = Path.GetFileName(assembly);
if (isDedup)
@@ -328,12 +431,23 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
aotArgs.Add("full");
}
+ if (parsedAotMode == MonoAotMode.Hybrid)
+ {
+ aotArgs.Add("hybrid");
+ }
+
if (parsedAotMode == MonoAotMode.FullInterp || parsedAotMode == MonoAotMode.JustInterp)
{
aotArgs.Add("interp");
}
- if (parsedOutputType == MonoAotOutputType.AsmOnly)
+ if (parsedOutputType == MonoAotOutputType.ObjectFile)
+ {
+ string objectFile = Path.Combine(OutputDir, Path.ChangeExtension(assemblyFilename, ".dll.o"));
+ aotArgs.Add($"outfile={objectFile}");
+ aotAssembly.SetMetadata("ObjectFile", objectFile);
+ }
+ else if (parsedOutputType == MonoAotOutputType.AsmOnly)
{
aotArgs.Add("asmonly");
@@ -341,11 +455,19 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
aotArgs.Add($"outfile={assemblerFile}");
aotAssembly.SetMetadata("AssemblerFile", assemblerFile);
}
- else
+ else if (parsedOutputType == MonoAotOutputType.Library)
{
- string objectFile = Path.Combine(OutputDir, Path.ChangeExtension(assemblyFilename, ".dll.o"));
- aotArgs.Add($"outfile={objectFile}");
- aotAssembly.SetMetadata("ObjectFile", objectFile);
+ string extension = parsedLibraryFormat switch {
+ MonoAotLibraryFormat.Dll => ".dll",
+ MonoAotLibraryFormat.Dylib => ".dylib",
+ MonoAotLibraryFormat.So => ".so",
+ _ => throw new ArgumentOutOfRangeException()
+ };
+ string libraryFileName = $"{LibraryFilePrefix}{assemblyFilename}{extension}";
+ string libraryFilePath = Path.Combine(OutputDir, libraryFileName);
+
+ aotArgs.Add($"outfile={libraryFilePath}");
+ aotAssembly.SetMetadata("LibraryFile", libraryFilePath);
}
if (UseLLVM)
@@ -405,7 +527,7 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
else
{
paths = $"{assemblyDir}{Path.PathSeparator}{monoPaths}";
- processArgs.Add(assemblyFilename);
+ processArgs.Add('"' + assemblyFilename + '"');
}
var envVariables = new Dictionary<string, string>
@@ -414,11 +536,20 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
{"MONO_ENV_OPTIONS", string.Empty} // we do not want options to be provided out of band to the cross compilers
};
+ var responseFileContent = string.Join(" ", processArgs);
+ var responseFilePath = Path.GetTempFileName();
+ using (var sw = new StreamWriter(responseFilePath, append: false, encoding: new UTF8Encoding(false)))
+ {
+ sw.WriteLine(responseFileContent);
+ }
+
+ Log.LogMessage(MessageImportance.Low, $"AOT compiler arguments: {responseFileContent}");
+
try
{
// run the AOT compiler
(int exitCode, string output) = Utils.TryRunProcess(CompilerBinaryPath,
- string.Join(" ", processArgs),
+ $"--response=\"{responseFilePath}\"",
envVariables,
assemblyDir,
silent: false,
@@ -436,6 +567,8 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
return false;
}
+ File.Delete(responseFilePath);
+
compiledAssemblies.Add(aotAssembly);
return true;
}
@@ -560,14 +693,23 @@ public enum MonoAotMode
JustInterp,
Full,
FullInterp,
+ Hybrid,
LLVMOnly,
LLVMOnlyInterp
}
public enum MonoAotOutputType
{
- Normal,
+ ObjectFile,
AsmOnly,
+ Library,
+}
+
+public enum MonoAotLibraryFormat
+{
+ Dll,
+ Dylib,
+ So,
}
public enum MonoAotModulesTableLanguage
diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.props b/src/tasks/AotCompilerTask/MonoAOTCompiler.props
index c6b2f2ad28e..4f2721d7483 100644
--- a/src/tasks/AotCompilerTask/MonoAOTCompiler.props
+++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.props
@@ -20,7 +20,7 @@
<MonoAOTCompilerDefaultAotArguments Condition="'$(TargetArchitecture)' == 'arm64'" Include="mtriple=aarch64-linux-android" />
<MonoAOTCompilerDefaultAotArguments Condition="'$(TargetArchitecture)' == 'x86'" Include="mtriple=i686-linux-android" />
<MonoAOTCompilerDefaultAotArguments Condition="'$(TargetArchitecture)' == 'x64'" Include="mtriple=x86_64-linux-android" />
- <MonoAOTCompilerDefaultAotArguments Include="static" />
+
<!-- Default trampolines run out for libraries tests -->
<MonoAOTCompilerDefaultAotArguments Include="nimt-trampolines=2000" />
<MonoAOTCompilerDefaultAotArguments Include="ntrampolines=10000" />