diff --git a/src/mono/msbuild/android/build/AndroidApp.targets b/src/mono/msbuild/android/build/AndroidApp.targets
index d40e5a2784004b..4bc558943daebe 100644
--- a/src/mono/msbuild/android/build/AndroidApp.targets
+++ b/src/mono/msbuild/android/build/AndroidApp.targets
@@ -76,6 +76,11 @@
<_AOTMode Condition="'$(ForceFullAOT)' == 'true'">Full
+
+ <_UsesRuntimeInitCallback>$(UsesRuntimeInitCallback)
+ <_UsesRuntimeInitCallback Condition="'$(_UsesRuntimeInitCallback)' == ''">true
+
+
@@ -85,6 +90,8 @@
+
+
@@ -133,6 +140,12 @@
Condition="'$(RunAOTCompilation)' == 'true'"
DependsOnTargets="_AndroidBeforeAotCompileApp">
+
+ <_EnableUnmanagedCallersOnlyMethodsExport>true
+ <_UseAotDataFile>$(UseAotDataFile)
+ <_UseAotDataFile Condition="'$(_UseAotDataFile)' == ''">false
+
+
@@ -147,10 +160,6 @@
-
- <_EnableUnmanagedCallersOnlyMethodsExport Condition="'$(_IsLibraryMode)' == 'true'">true
-
-
diff --git a/src/mono/msbuild/apple/build/AppleApp.targets b/src/mono/msbuild/apple/build/AppleApp.targets
index bf637dcc8b7ca8..93f4113c645360 100644
--- a/src/mono/msbuild/apple/build/AppleApp.targets
+++ b/src/mono/msbuild/apple/build/AppleApp.targets
@@ -91,8 +91,12 @@
<_AOTMode Condition="'$(UseMonoJustInterp)' == 'true'">JustInterp
-
- <_EnableUnmanagedCallersOnlyMethodsExport Condition="'$(_IsLibraryMode)' == 'true'">true
+
+ <_EnableUnmanagedCallersOnlyMethodsExport>true
+ <_UseAotDataFile>$(UseAotDataFile)
+ <_UseAotDataFile Condition="'$(_UseAotDataFile)' == ''">false
+ <_UsesRuntimeInitCallback>$(UsesRuntimeInitCallback)
+ <_UsesRuntimeInitCallback Condition="'$(_UsesRuntimeInitCallback)' == ''">true
@@ -104,6 +108,8 @@
+
+
@@ -166,6 +172,7 @@
Mode="$(_AOTMode)"
OutputDir="$(_MobileIntermediateOutputPath)"
OutputType="AsmOnly"
+ UseAotDataFile="$(_UseAotDataFile)"
UseLLVM="$(MonoEnableLLVM)">
diff --git a/src/mono/msbuild/common/LibraryBuilder.targets b/src/mono/msbuild/common/LibraryBuilder.targets
index ae920b8dec07aa..5b4da1edea3f99 100644
--- a/src/mono/msbuild/common/LibraryBuilder.targets
+++ b/src/mono/msbuild/common/LibraryBuilder.targets
@@ -8,6 +8,8 @@
<_IsSharedLibrary>false
<_IsSharedLibrary Condition="'$(NativeLib)' == 'shared'">true
+ <_UsesCustomRuntimeInitCallback>false
+ <_UsesCustomRuntimeInitCallback Condition="$(CustomRuntimeInitCallback) != ''">true
@@ -17,15 +19,18 @@
+ TargetOS="$(TargetOS)"
+ UsesCustomRuntimeInitCallback="$(_UsesCustomRuntimeInitCallback)"
+ UsesRuntimeInitCallback="$(_UsesRuntimeInitCallback)">
diff --git a/src/tasks/LibraryBuilder/LibraryBuilder.cs b/src/tasks/LibraryBuilder/LibraryBuilder.cs
index 0b3489db177ff6..dd3a51324f5a8e 100644
--- a/src/tasks/LibraryBuilder/LibraryBuilder.cs
+++ b/src/tasks/LibraryBuilder/LibraryBuilder.cs
@@ -19,6 +19,8 @@ public class LibraryBuilderTask : AppBuilderTask
private string cmakeProjectLanguages = "";
private string targetOS = "";
+ private bool usesAOTDataFile;
+ private List exportedAssemblies = new List();
///
/// The name of the library being generated
@@ -66,6 +68,23 @@ public bool IsSharedLibrary
}
}
+ ///
+ /// Determines whether or not the mono runtime auto initialization
+ /// template, autoinit.c, is used.
+ ///
+ public bool UsesCustomRuntimeInitCallback { get; set; }
+
+ ///
+ /// Determines if there is a mono runtime init callback
+ ///
+ public bool UsesRuntimeInitCallback { get; set; }
+
+ ///
+ /// The environment variable name that will point to where assemblies
+ /// are located on the app host device.
+ ///
+ public string? AssembliesLocation { get; set; }
+
public bool StripDebugSymbols { get; set; }
///
@@ -113,6 +132,17 @@ public override bool Execute()
GatherAotSourcesObjects(aotSources, aotObjects, extraSources, linkerArgs);
GatherLinkerArgs(linkerArgs);
+ File.WriteAllText(Path.Combine(OutputDirectory, "library-builder.h"),
+ Utils.GetEmbeddedResource("library-builder.h"));
+
+ GenerateAssembliesLoader();
+
+ if (UsesRuntimeInitCallback && !UsesCustomRuntimeInitCallback)
+ {
+ WriteAutoInitializationFromTemplate();
+ extraSources.AppendLine(" autoinit.c");
+ }
+
WriteCMakeFileFromTemplate(aotSources.ToString(), aotObjects.ToString(), extraSources.ToString(), linkerArgs.ToString());
OutputPath = BuildLibrary();
@@ -122,14 +152,18 @@ public override bool Execute()
private void GatherAotSourcesObjects(StringBuilder aotSources, StringBuilder aotObjects, StringBuilder extraSources, StringBuilder linkerArgs)
{
List exportedSymbols = new List();
- List exportedAssemblies = new List();
bool hasExports = false;
foreach (CompiledAssembly compiledAssembly in CompiledAssemblies)
{
if (!string.IsNullOrEmpty(compiledAssembly.AssemblerFile))
{
- aotSources.AppendLine(compiledAssembly.AssemblerFile);
+ aotSources.AppendLine($" {compiledAssembly.AssemblerFile}");
+ }
+
+ if (!usesAOTDataFile && !string.IsNullOrEmpty(compiledAssembly.DataFile))
+ {
+ usesAOTDataFile = true;
}
if (!string.IsNullOrEmpty(compiledAssembly.LlvmObjectFile))
@@ -145,10 +179,14 @@ private void GatherAotSourcesObjects(StringBuilder aotSources, StringBuilder aot
if (symbolsAdded > 0)
{
- exportedAssemblies.Add(Path.GetFileName(compiledAssembly.Path));
+ exportedAssemblies.Add(Path.GetFileNameWithoutExtension(compiledAssembly.Path));
}
}
}
+ if (IsSharedLibrary && exportedAssemblies.Count == 0)
+ {
+ throw new LogAsErrorException($"None of the compiled assemblies contain exported symbols. Resulting shared library would be unusable.");
+ }
// for android, all symbols to keep go in one linker script
//
@@ -167,11 +205,9 @@ private void GatherAotSourcesObjects(StringBuilder aotSources, StringBuilder aot
WriteExportedSymbolsArg(MobileSymbolFileName, linkerArgs);
}
- WriteAssembliesToLoadList(exportedAssemblies);
-
foreach (ITaskItem item in ExtraSources)
{
- extraSources.AppendLine(item.ItemSpec);
+ extraSources.AppendLine($" {item.ItemSpec}");
}
}
@@ -226,8 +262,30 @@ private static void WriteLinkerScriptFile(string exportsFile, List expor
.Replace("%GLOBAL_SYMBOLS%", globalExports));
}
+ private void WriteAutoInitializationFromTemplate()
+ {
+ File.WriteAllText(Path.Combine(OutputDirectory, "autoinit.c"),
+ Utils.GetEmbeddedResource("autoinit.c")
+ .Replace("%ASSEMBLIES_LOCATION%", !string.IsNullOrEmpty(AssembliesLocation) ? AssembliesLocation : "DOTNET_LIBRARY_ASSEMBLY_PATH")
+ .Replace("%RUNTIME_IDENTIFIER%", RuntimeIdentifier));
+ }
+
+ private void GenerateAssembliesLoader()
+ {
+ var assemblyPreloaders = new List();
+ foreach (string exportedAssembly in exportedAssemblies)
+ {
+ assemblyPreloaders.Add($"preload_assembly(\"{exportedAssembly}\");");
+ }
+
+ File.WriteAllText(Path.Combine(OutputDirectory, "preloaded-assemblies.c"),
+ Utils.GetEmbeddedResource("preloaded-assemblies.c")
+ .Replace("%ASSEMBLIES_PRELOADER%", string.Join("\n ", assemblyPreloaders)));
+ }
+
private void WriteCMakeFileFromTemplate(string aotSources, string aotObjects, string extraSources, string linkerArgs)
{
+ string extraDefinitions = GenerateExtraDefinitions();
// BundleDir
File.WriteAllText(Path.Combine(OutputDirectory, "CMakeLists.txt"),
Utils.GetEmbeddedResource("CMakeLists.txt.template")
@@ -237,35 +295,21 @@ private void WriteCMakeFileFromTemplate(string aotSources, string aotObjects, st
.Replace("%MonoInclude%", MonoRuntimeHeaders)
.Replace("%AotSources%", aotSources)
.Replace("%AotObjects%", aotObjects)
+ .Replace("%ExtraDefinitions%", extraDefinitions)
.Replace("%ExtraSources%", extraSources)
.Replace("%LIBRARY_LINKER_ARGS%", linkerArgs));
}
- private void WriteAssembliesToLoadList(List assemblies)
+ private string GenerateExtraDefinitions()
{
- string content;
+ var extraDefinitions = new StringBuilder();
- if (assemblies.Count == 0)
- {
- content = " return NULL;";
- }
- else
+ if (usesAOTDataFile)
{
- StringBuilder sb = new StringBuilder();
- sb.AppendLine($" char** assembly_list = (char**)malloc({assemblies.Count.ToString()} * sizeof(char*));");
-
- for (int i = 0; i < assemblies.Count; i++)
- {
- sb.AppendLine($" assembly_list[{i.ToString()}] = \"{assemblies[i]}\";");
- }
-
- sb.AppendLine(" return assembly_list;");
- content = sb.ToString();
+ extraDefinitions.AppendLine("add_definitions(-DUSES_AOT_DATA=1)");
}
- File.WriteAllText(Path.Combine(OutputDirectory, "assembly_list.c"),
- Utils.GetEmbeddedResource("assembly_list.c")
- .Replace("%LOADABLE_ASSEMBLIES%", content));
+ return extraDefinitions.ToString();
}
private string BuildLibrary()
diff --git a/src/tasks/LibraryBuilder/LibraryBuilder.csproj b/src/tasks/LibraryBuilder/LibraryBuilder.csproj
index c2a8ae77a3c51e..bdd1543fd13a53 100644
--- a/src/tasks/LibraryBuilder/LibraryBuilder.csproj
+++ b/src/tasks/LibraryBuilder/LibraryBuilder.csproj
@@ -19,6 +19,7 @@
+
diff --git a/src/tasks/LibraryBuilder/Templates/CMakeLists.txt.template b/src/tasks/LibraryBuilder/Templates/CMakeLists.txt.template
index 1fa43e84a9edeb..8f138c5fd25445 100644
--- a/src/tasks/LibraryBuilder/Templates/CMakeLists.txt.template
+++ b/src/tasks/LibraryBuilder/Templates/CMakeLists.txt.template
@@ -5,21 +5,21 @@ project(%LIBRARY_NAME%)
enable_language(%CMAKE_LANGS%)
set(DOTNET_AOT_SOURCES
- %AotSources%
+%AotSources%
)
set(DOTNET_AOT_OBJECTS
- %AotObjects%
+%AotObjects%
)
set(DOTNET_EXTRA_SOURCES
- %ExtraSources%
- assembly_list.c
-)
+ library-builder.h
+ preloaded-assemblies.c
+%ExtraSources%)
include_directories("%MonoInclude%")
add_library(
aot_library STATIC
- ${DOTNET_AOT_SOURCES}
+ ${DOTNET_AOT_SOURCES}
)
target_link_libraries(
aot_library
@@ -35,9 +35,10 @@ add_library(
if(TARGETS_ANDROID)
set(MOBILE_SYSTEM_LIBS
libz.so
- log
+ log
)
-else()
+ add_definitions(-DHOST_ANDROID=1)
+elseif(TARGETS_APPLE_MOBILE)
set(MOBILE_SYSTEM_LIBS
"-framework Foundation"
"-framework Security"
@@ -46,12 +47,16 @@ else()
"-lc++"
"-liconv"
)
+ add_definitions(-DHOST_APPLE_MOBILE=1)
+else()
+ message(FATAL_ERROR "Unsupported Platform. Ensure the TargetOS is supported by the LibraryBuilder and the platform specific libs are added here.")
endif()
+%ExtraDefinitions%
+
target_link_libraries(
%LIBRARY_NAME%
PUBLIC
aot_library
${MOBILE_SYSTEM_LIBS}
- %LIBRARY_LINKER_ARGS%
-)
+%LIBRARY_LINKER_ARGS%)
diff --git a/src/tasks/LibraryBuilder/Templates/assembly_list.c b/src/tasks/LibraryBuilder/Templates/assembly_list.c
deleted file mode 100644
index ef2168d3e50bf7..00000000000000
--- a/src/tasks/LibraryBuilder/Templates/assembly_list.c
+++ /dev/null
@@ -1,9 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-#include
-#include
-
-char** get_loadable_assemblies ()
-{
-%LOADABLE_ASSEMBLIES%
-}
\ No newline at end of file
diff --git a/src/tasks/LibraryBuilder/Templates/autoinit.c b/src/tasks/LibraryBuilder/Templates/autoinit.c
new file mode 100644
index 00000000000000..6fd37510d00a1c
--- /dev/null
+++ b/src/tasks/LibraryBuilder/Templates/autoinit.c
@@ -0,0 +1,149 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+#include
+#include
+#include
+#include
+#include
+#include
+#if defined(USES_AOT_DATA)
+#include
+#include
+#include
+#endif
+
+#include
+#include
+#include
+
+#include "library-builder.h"
+
+static void
+cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data)
+{
+ free ((void *)args->runtimeconfig.name.path);
+ free (args);
+ free (user_data);
+}
+
+static void
+initialize_runtimeconfig (const char *bundle_path)
+{
+ char *file_name = "runtimeconfig.bin";
+ size_t str_len = sizeof (char) * (strlen (bundle_path) + strlen (file_name) + 2); // +1 "/", +1 null-terminating char
+ char *file_path = (char *)malloc (str_len);
+ if (!file_path)
+ LOG_ERROR ("Out of memory.\n");
+
+ int num_char = snprintf (file_path, str_len, "%s/%s", bundle_path, file_name);
+ if (num_char <= 0 || num_char >= str_len)
+ LOG_ERROR ("Encoding error while formatting '%s' and '%s' into \"%%s/%%s\".\n", bundle_path, file_name);
+
+ struct stat buffer;
+
+ if (stat (file_path, &buffer) == 0) {
+ MonovmRuntimeConfigArguments *arg = (MonovmRuntimeConfigArguments *)malloc (sizeof (MonovmRuntimeConfigArguments));
+ if (!arg)
+ LOG_ERROR ("Out of memory.\n");
+
+ arg->kind = 0;
+ arg->runtimeconfig.name.path = file_path;
+ monovm_runtimeconfig_initialize (arg, cleanup_runtime_config, NULL);
+ } else {
+ free (file_path);
+ }
+}
+
+static void
+initialize_appctx_env_variables (const char *bundle_path)
+{
+ const char *appctx_keys[2], *appctx_values[2];
+
+ appctx_keys[0] = "RUNTIME_IDENTIFIER";
+ appctx_values[0] = "%RUNTIME_IDENTIFIER%";
+
+ appctx_keys[1] = "APP_CONTEXT_BASE_DIRECTORY";
+ appctx_values[1] = bundle_path;
+
+ monovm_initialize (2, appctx_keys, appctx_values);
+}
+
+#if defined(USES_AOT_DATA)
+static unsigned char *
+load_aot_data (MonoAssembly *assembly, int size, void *user_data, void **out_handle)
+{
+ *out_handle = NULL;
+ const char *bundle_path = (const char*)user_data;
+
+ MonoAssemblyName *assembly_name = mono_assembly_get_name (assembly);
+ const char *aname = mono_assembly_name_get_name (assembly_name);
+
+ size_t str_len = sizeof (char) * (strlen (bundle_path) + strlen (aname) + 10); // +1 "/", +8 ".aotdata", +1 null-terminating char
+ char *file_path = (char *)malloc (str_len);
+ if (!file_path)
+ LOG_ERROR ("Out of memory.\n");
+
+ int res = snprintf (file_path, str_len, "%s/%s.aotdata", bundle_path, aname);
+ if (res <= 0 || res >= str_len)
+ LOG_ERROR ("Encoding error while formatting '%s' and '%s' into \"%%s/%%s\".\n", bundle_path, aname);
+
+ int fd = open (file_path, O_RDONLY);
+ if (fd < 0)
+ LOG_ERROR ("Could not open file '%s'.\n", file_path);
+
+ void *ptr = mmap (NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+ close (fd);
+ if (ptr == MAP_FAILED)
+ LOG_ERROR ("Could not map file '%s' to memory.\n", file_path);
+
+ *out_handle = ptr;
+ return (unsigned char *) ptr;
+}
+
+static void
+free_aot_data (MonoAssembly *assembly, int size, void *user_data, void *handle)
+{
+ munmap (handle, size);
+}
+#endif
+
+static void
+runtime_init_callback ()
+{
+ const char *assemblies_location = getenv ("%ASSEMBLIES_LOCATION%");
+ if (!assemblies_location || assemblies_location[0] == '\0')
+ assemblies_location = "./";
+
+ // Don't free as load_aot_data may be called later on, if used.
+ const char *bundle_path = strdup (assemblies_location);
+ if (!bundle_path)
+ LOG_ERROR ("Out of memory.\n");
+
+ initialize_runtimeconfig (bundle_path);
+
+ initialize_appctx_env_variables (bundle_path);
+
+ register_aot_modules ();
+
+ mono_set_assemblies_path (bundle_path);
+
+ mono_jit_set_aot_only (true);
+
+#if defined(USES_AOT_DATA)
+ mono_install_load_aot_data_hook (load_aot_data, free_aot_data, bundle_path);
+#endif
+
+ mono_set_signal_chaining (true);
+
+ MonoDomain *domain = mono_jit_init ("mono.self.contained.library");
+ if (!domain)
+ LOG_ERROR ("Could not auto initialize runtime.\n");
+
+ preload_assemblies_with_exported_symbols ();
+}
+
+void __attribute__((constructor))
+autoinit ()
+{
+ mono_set_runtime_init_callback (&runtime_init_callback);
+}
diff --git a/src/tasks/LibraryBuilder/Templates/library-builder.h b/src/tasks/LibraryBuilder/Templates/library-builder.h
new file mode 100644
index 00000000000000..c0dee67be95adc
--- /dev/null
+++ b/src/tasks/LibraryBuilder/Templates/library-builder.h
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef __MONO_LIBRARY_BUILDER_H__
+#define __MONO_LIBRARY_BUILDER_H__
+
+#include
+
+#if defined(HOST_ANDROID)
+
+#include
+
+#define LOG_ERROR(fmt, ...) \
+ do \
+ { \
+ __android_log_print(ANDROID_LOG_ERROR, "MONO_SELF_CONTAINED_LIBRARY", fmt, ##__VA_ARGS__); \
+ abort (); \
+ } while (0)
+
+#elif defined(HOST_APPLE_MOBILE)
+
+#include
+
+#define LOG_ERROR(fmt, ...) \
+ do \
+ { \
+ os_log_error (OS_LOG_DEFAULT, fmt, ##__VA_ARGS__); \
+ abort (); \
+ } while (0)
+
+#else
+
+#error Unsupported Host Platform. Ensure the hosting platform is supported by the LibraryBuilder and the appropriate logging functions are added.
+
+#endif
+
+void register_aot_modules (void);
+void preload_assemblies_with_exported_symbols ();
+typedef void (*MonoRuntimeInitCallback) (void);
+void mono_set_runtime_init_callback (MonoRuntimeInitCallback callback);
+
+#endif /*__MONO_LIBRARY_BUILDER_H__*/
diff --git a/src/tasks/LibraryBuilder/Templates/preloaded-assemblies.c b/src/tasks/LibraryBuilder/Templates/preloaded-assemblies.c
new file mode 100644
index 00000000000000..71be26d870dc0b
--- /dev/null
+++ b/src/tasks/LibraryBuilder/Templates/preloaded-assemblies.c
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+#include
+
+#include
+
+#include "library-builder.h"
+
+static void
+preload_assembly (const char* filename)
+{
+ MonoAssembly *assembly = mono_assembly_load_with_partial_name (filename, NULL);
+ if (!assembly)
+ LOG_ERROR ("Could not open assembly '%s'.\n", filename);
+}
+
+void
+preload_assemblies_with_exported_symbols ()
+{
+ %ASSEMBLIES_PRELOADER%
+}
\ No newline at end of file