Skip to content

Commit

Permalink
[tasks] Extend auto initialization template to account for customization
Browse files Browse the repository at this point in the history
  • Loading branch information
mdh1418 committed Mar 8, 2023
1 parent bc86f2b commit bef3de9
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 35 deletions.
3 changes: 2 additions & 1 deletion src/mono/msbuild/android/build/AndroidApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@
<MonoAOTCompilerDefaultAotArguments Include="static" />
<MonoAOTCompilerDefaultAotArguments Include="dwarfdebug" />
<MonoAOTCompilerDefaultAotArguments Condition="'$(_IsLibraryMode)' == 'true'" Include="direct-icalls" />
<MonoAOTCompilerDefaultAotArguments Condition="'$(_IsLibraryMode)' == 'true'" Include="runtime-init-callback" />
<MonoAOTCompilerDefaultAotArguments Condition="'$(_IsLibraryMode)' == 'true' and $(CustomRuntimeInitCallback) == ''" Include="runtime-init-callback" />
<MonoAOTCompilerDefaultAotArguments Condition="'$(_IsLibraryMode)' == 'true' and $(CustomRuntimeInitCallback) != ''" Include="runtime-init-callback=$(CustomRuntimeInitCallback)" />

<MonoAOTCompilerDefaultAotArguments Include="nimt-trampolines=2000" />
<MonoAOTCompilerDefaultAotArguments Include="ntrampolines=10000" />
Expand Down
5 changes: 4 additions & 1 deletion src/mono/msbuild/common/LibraryBuilder.targets
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
<PropertyGroup>
<_IsSharedLibrary>false</_IsSharedLibrary>
<_IsSharedLibrary Condition="'$(NativeLib)' == 'shared'">true</_IsSharedLibrary>
<_UsesCustomRuntimeInitCallback>false</_UsesCustomRuntimeInitCallback>
<_UsesCustomRuntimeInitCallback Condition="$(CustomRuntimeInitCallback) != ''">true</_UsesCustomRuntimeInitCallback>
</PropertyGroup>

<ItemGroup>
Expand All @@ -25,7 +27,8 @@
OutputDirectory="$(BundleDir)"
RuntimeIdentifier="$(RuntimeIdentifier)"
RuntimeLibraries="@(_RuntimeLibraries)"
TargetOS="$(TargetOS)">
TargetOS="$(TargetOS)"
UsesCustomRuntimeInitCallback="$(_UsesCustomRuntimeInitCallback)">
<Output TaskParameter="OutputPath" PropertyName="LibraryOutputPath" />
</LibraryBuilderTask>
</Target>
Expand Down
105 changes: 101 additions & 4 deletions src/tasks/LibraryBuilder/LibraryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,26 @@ public bool IsSharedLibrary
}
}

/// <summary>
/// Determines whether or not the mono runtime auto initialization
/// tremplate, autoinit.c, is used.
/// </summary>
public bool UsesCustomRuntimeInitCallback { get; set; }

public string? AssetsPath { get; set; }

/// <summary>
/// </summary>
public ITaskItem[] AppContextKeys { get; set; } = Array.Empty<ITaskItem>();

/// <summary>
/// </summary>
public ITaskItem[] AppContextValues { get; set; } = Array.Empty<ITaskItem>();

/// <summary>
/// </summary>
public string? RuntimeConfigBinFile { get; set; }

public bool StripDebugSymbols { get; set; }

/// <summary>
Expand Down Expand Up @@ -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<string> exportedAssemblies = new List<string>();

private void GatherAotSourcesObjects(StringBuilder aotSources, StringBuilder aotObjects, StringBuilder extraSources, StringBuilder linkerArgs)
{
List<string> exportedSymbols = new List<string>();
List<string> exportedAssemblies = new List<string>();
bool hasExports = false;

foreach (CompiledAssembly compiledAssembly in CompiledAssemblies)
Expand Down Expand Up @@ -226,6 +253,79 @@ private static void WriteLinkerScriptFile(string exportsFile, List<string> 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
Expand All @@ -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<string> assemblies)
Expand Down
1 change: 1 addition & 0 deletions src/tasks/LibraryBuilder/LibraryBuilder.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<Compile Include="..\Common\Builders\AppBuilderTask.cs" />
<Compile Include="..\Common\Builders\AndroidProject.cs" />
<Compile Include="..\Common\Builders\CompiledAssembly.cs" />
<Compile Include="..\Common\LogAsErrorException.cs" />
<Compile Include="..\AppleAppBuilder\TargetOS.cs" />
<Compile Include="..\AppleAppBuilder\Xcode.cs" />
</ItemGroup>
Expand Down
54 changes: 25 additions & 29 deletions src/tasks/LibraryBuilder/Templates/autoinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,43 +13,33 @@
#include <mono/metadata/assembly.h>
#include <mono/metadata/mono-debug.h>

// 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,
void **file_base, char *sym_name,
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*
Expand Down Expand Up @@ -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);

Expand All @@ -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);
}

Expand Down

0 comments on commit bef3de9

Please sign in to comment.