diff --git a/src/mono/msbuild/android/build/AndroidApp.targets b/src/mono/msbuild/android/build/AndroidApp.targets
index 7fb35a9c4d3bfe..e1a5363d22fbe4 100644
--- a/src/mono/msbuild/android/build/AndroidApp.targets
+++ b/src/mono/msbuild/android/build/AndroidApp.targets
@@ -85,7 +85,8 @@
-
+
+
diff --git a/src/mono/msbuild/common/LibraryBuilder.targets b/src/mono/msbuild/common/LibraryBuilder.targets
index eacc9e2cae7544..2d54b6a07dd161 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
@@ -25,7 +27,8 @@
OutputDirectory="$(BundleDir)"
RuntimeIdentifier="$(RuntimeIdentifier)"
RuntimeLibraries="@(_RuntimeLibraries)"
- TargetOS="$(TargetOS)">
+ TargetOS="$(TargetOS)"
+ UsesCustomRuntimeInitCallback="$(_UsesCustomRuntimeInitCallback)">
diff --git a/src/tasks/LibraryBuilder/LibraryBuilder.cs b/src/tasks/LibraryBuilder/LibraryBuilder.cs
index 7b5fed50e618bc..bec8d46b3b1d17 100644
--- a/src/tasks/LibraryBuilder/LibraryBuilder.cs
+++ b/src/tasks/LibraryBuilder/LibraryBuilder.cs
@@ -66,6 +66,26 @@ public bool IsSharedLibrary
}
}
+ ///
+ /// Determines whether or not the mono runtime auto initialization
+ /// tremplate, autoinit.c, is used.
+ ///
+ public bool UsesCustomRuntimeInitCallback { get; set; }
+
+ public string? AssetsPath { get; set; }
+
+ ///
+ ///
+ public ITaskItem[] AppContextKeys { get; set; } = Array.Empty();
+
+ ///
+ ///
+ public ITaskItem[] AppContextValues { get; set; } = Array.Empty();
+
+ ///
+ ///
+ public string? RuntimeConfigBinFile { get; set; }
+
public bool StripDebugSymbols { get; set; }
///
@@ -113,16 +133,23 @@ public override bool Execute()
GatherAotSourcesObjects(aotSources, aotObjects, extraSources, linkerArgs);
GatherLinkerArgs(linkerArgs);
+ if (!UsesCustomRuntimeInitCallback)
+ {
+ WriteAutoInitializationFromTemplate();
+ }
+
WriteCMakeFileFromTemplate(aotSources.ToString(), aotObjects.ToString(), extraSources.ToString(), linkerArgs.ToString());
OutputPath = BuildLibrary();
return true;
}
+
+ private List exportedAssemblies = new List();
+
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)
@@ -226,6 +253,79 @@ private static void WriteLinkerScriptFile(string exportsFile, List expor
.Replace("%GLOBAL_SYMBOLS%", globalExports));
}
+ private void WriteAutoInitializationFromTemplate()
+ {
+ string appContextEnvVariables = GenerateAppContextEnvVariables();
+ string assembliesLoader = GenerateAssembliesLoader();
+ string assetsPath = GenerateAssetsPath();
+ string runtimeConfig = GenerateRuntimeConfig();
+ File.WriteAllText(Path.Combine(OutputDirectory, "autoinit.c"),
+ Utils.GetEmbeddedResource("autoinit.c")
+ .Replace("%APPCTX_ENV_VARIABLES%", appContextEnvVariables)
+ .Replace("%ASSEMBLIES_LOADER%", assembliesLoader)
+ .Replace("%ASSETS_PATH%", assetsPath)
+ .Replace("%RUNTIME_CONFIG%", runtimeConfig));
+ }
+
+ private string GenerateAssembliesLoader()
+ {
+ var assembliesLoader = new StringBuilder();
+ foreach (string exportedAssembly in exportedAssemblies)
+ {
+ assembliesLoader.AppendLine($" mono_assembly_open(\"{exportedAssembly}\", NULL);");
+ }
+ return assembliesLoader.ToString();
+ }
+
+ private string GenerateAssetsPath()
+ {
+ return AssetsPath ?? "DOTNET_ASSETS_PATH";
+ }
+
+ private string GenerateRuntimeConfig()
+ {
+ if (string.IsNullOrEmpty(RuntimeConfigBinFile))
+ return " return;";
+
+ var runtimeConfig = new StringBuilder();
+ runtimeConfig.Append($" char *file_name = {RuntimeConfigBinFile};");
+ runtimeConfig.Append(" int str_len = strlen (bundle_path) + strlen (file_name) + 1; // +1 is for the \"/\"");
+ runtimeConfig.Append(" char *file_path = (char *)malloc (sizeof (char) * (str_len +1)); // +1 is for the terminating null character");
+ runtimeConfig.Append(" int num_char = snprintf (file_path, (str_len + 1), \"%s/%s\", bundle_path, file_name);");
+ runtimeConfig.Append(" struct stat buffer;\n");
+ runtimeConfig.Append(" assert (num_char > 0 && num_char == str_len);\n");
+ runtimeConfig.Append(" if (stat (file_path, &buffer) == 0) {");
+ runtimeConfig.Append(" MonovmRuntimeConfigArguments *arg = (MonovmRuntimeConfigArguments *)malloc (sizeof (MonovmRuntimeConfigArguments));");
+ runtimeConfig.Append(" arg->kind = 0;");
+ runtimeConfig.Append(" arg->runtimeconfig.name.path = file_path;");
+ runtimeConfig.Append(" monovm_runtimeconfig_initialize (arg, cleanup_runtime_config, file_path);");
+ runtimeConfig.Append(" } else {");
+ runtimeConfig.Append(" free (file_path);");
+ runtimeConfig.Append(" }");
+ return runtimeConfig.ToString();
+ }
+
+ private string GenerateAppContextEnvVariables()
+ {
+ if (AppContextKeys.Length != AppContextValues.Length)
+ {
+ throw new LogAsErrorException($"'{nameof(AppContextKeys)}' length does not match '{nameof(AppContextValues)}' length. {AppContextKeys.Length} != {AppContextValues.Length}");
+ }
+
+ int numArgs = AppContextKeys.Length;
+ var appContextEnvVariables = new StringBuilder();
+
+ appContextEnvVariables.AppendLine($" const char **appctx_keys, **appctx_values = (char**)malloc({numArgs} * sizeof(char*));");
+ for (int i = 0; i < numArgs; i++)
+ {
+ appContextEnvVariables.AppendLine($" appctx_keys[{i}] = \"{AppContextKeys[i]}\";");
+ appContextEnvVariables.AppendLine($" appctx_values[{i}] = \"{AppContextValues[i]}\";");
+ }
+ appContextEnvVariables.AppendLine($" monovm_initialize({numArgs}, appctx_keys, appctx_values);");
+
+ return appContextEnvVariables.ToString();
+ }
+
private void WriteCMakeFileFromTemplate(string aotSources, string aotObjects, string extraSources, string linkerArgs)
{
// BundleDir
@@ -239,9 +339,6 @@ private void WriteCMakeFileFromTemplate(string aotSources, string aotObjects, st
.Replace("%AotObjects%", aotObjects)
.Replace("%ExtraSources%", extraSources)
.Replace("%LIBRARY_LINKER_ARGS%", linkerArgs));
-
- File.WriteAllText(Path.Combine(OutputDirectory, "autoinit.c"),
- Utils.GetEmbeddedResource("autoinit.c"));
}
private void WriteAssembliesToLoadList(List assemblies)
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/autoinit.c b/src/tasks/LibraryBuilder/Templates/autoinit.c
index 6746a15a3811da..f18140758cef11 100644
--- a/src/tasks/LibraryBuilder/Templates/autoinit.c
+++ b/src/tasks/LibraryBuilder/Templates/autoinit.c
@@ -13,10 +13,7 @@
#include
#include
-// TODO grab the directory where the assemblies are placed on device and remove path hardcode
-static char *bundle_path = "/data/user/0/net.dot.Android.Device_Emulator.Aot_Llvm.Test/files";
-
-#define RUNTIMECONFIG_BIN_FILE "runtimeconfig.bin"
+static char *bundle_path;
void register_aot_modules (void);
bool monoeg_g_module_address (void *addr, char *file_name, size_t file_name_len,
@@ -24,32 +21,25 @@ bool monoeg_g_module_address (void *addr, char *file_name, size_t file_name_len,
size_t sym_name_len, void **sym_addr);
char *mono_path_resolve_symlinks(const char *path);
char *monoeg_g_path_get_dirname (const char *filename);
+char *monoeg_g_getenv (const char *variable);
-void
+static void
cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data)
{
free (args);
free (user_data);
}
-void register_bundled_modules ()
+static void
+initialize_runtimeconfig ()
{
- char *file_name = RUNTIMECONFIG_BIN_FILE;
- int str_len = strlen (bundle_path) + strlen (file_name) + 1; // +1 is for the "/"
- char *file_path = (char *)malloc (sizeof (char) * (str_len +1)); // +1 is for the terminating null character
- int num_char = snprintf (file_path, (str_len + 1), "%s/%s", bundle_path, file_name);
- struct stat buffer;
-
- assert (num_char > 0 && num_char == str_len);
+%RUNTIME_CONFIG%
+}
- if (stat (file_path, &buffer) == 0) {
- MonovmRuntimeConfigArguments *arg = (MonovmRuntimeConfigArguments *)malloc (sizeof (MonovmRuntimeConfigArguments));
- arg->kind = 0;
- arg->runtimeconfig.name.path = file_path;
- monovm_runtimeconfig_initialize (arg, cleanup_runtime_config, file_path);
- } else {
- free (file_path);
- }
+static void
+initialize_appctx_env_variables ()
+{
+%APPCTX_ENV_VARIABLES%
}
static MonoAssembly*
@@ -143,14 +133,18 @@ free_aot_data (MonoAssembly *assembly, int size, void *user_data, void *handle)
munmap (handle, size);
}
-void runtime_init_callback ()
+void
+runtime_init_callback ()
{
+ initialize_runtimeconfig ();
+
+ initialize_appctx_env_variables ();
+
register_aot_modules ();
- register_bundled_modules ();
+ // register all bundled modules
- char *assemblyPath = assemblies_dir ();
- mono_set_assemblies_path ((assemblyPath && assemblyPath[0] != '\0') ? assemblyPath : "./");
+ mono_set_assemblies_path ((bundle_path && bundle_path[0] != '\0') ? bundle_path : "./");
mono_jit_set_aot_only (true);
@@ -168,15 +162,17 @@ void runtime_init_callback ()
mono_install_load_aot_data_hook (load_aot_data, free_aot_data, NULL);
+ mono_set_signal_chaining (true);
+
mono_jit_init ("dotnet.android"); // Pass in via LibraryBuilder?
- // Load assemblies with UnmanagedCallersOnly exported methods
- // TODO leverage get_loadable_assemblies and call mono_assembly_open on each
- mono_assembly_open("Android.Device_Emulator.Aot_Llvm.Test.dll", NULL);
+%ASSEMBLIES_LOADER%
}
-void init_mono_runtime ()
+void
+init_mono_runtime ()
{
+ bundle_path = monoeg_g_getenv("%ASSETS_PATH%");
mono_set_runtime_init_callback (&runtime_init_callback);
}