Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tasks] Add auto runtime initialization template to LibraryBuilder #83050

Merged
merged 30 commits into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
97b2c35
[tasks] Add auto runtime initialization template to LibraryBuilder
mdh1418 Feb 21, 2023
bc86f2b
Grab shared library directory
mdh1418 Mar 7, 2023
bef3de9
[tasks] Extend auto initialization template to account for customization
mdh1418 Mar 8, 2023
2458541
Revert "Grab shared library directory"
mdh1418 Mar 8, 2023
6dc3895
Remove platform specific naming
mdh1418 Mar 8, 2023
d772bf8
[tasks] Move App Context setup back to autoinit.c
mdh1418 Mar 10, 2023
bb228c4
Remove registering bundled modules and debugging until they can be va…
mdh1418 Mar 10, 2023
c47e5d5
Remove unnecessary wrapper
mdh1418 Mar 10, 2023
806c55a
Grab bundle_path later without eglib
mdh1418 Mar 10, 2023
108489f
Rename AssetsPath to AssembliesLocation
mdh1418 Mar 10, 2023
3b71e95
Move assembly loading into separate function
mdh1418 Mar 10, 2023
89c2c8e
Remove unnecessary function
mdh1418 Mar 10, 2023
f5598a1
Cleanup CMakeLists template indentation
mdh1418 Mar 10, 2023
b9a8c7c
Add dotnet header to autoinit.c
mdh1418 Mar 10, 2023
50f24b0
Default bundle_path if assemblies path environment variable not set
mdh1418 Mar 10, 2023
5bd4aa3
Pass bundle_path to load assemblies
mdh1418 Mar 11, 2023
7fe528f
Add logging and abort on failures
mdh1418 Mar 13, 2023
cbdaa3e
Load assemblies with partial name
mdh1418 Mar 14, 2023
c29d0cf
Clean up targets and unneeded properties
mdh1418 Mar 14, 2023
46218d5
Rename source file
mdh1418 Mar 14, 2023
bc5662f
Remove preload hook and make out of memory error more generic
mdh1418 Mar 14, 2023
5c2135f
Throw when no exported symbols are found
mdh1418 Mar 14, 2023
5b6cb51
Remove aot data load prehook and aotdata generation
mdh1418 Mar 14, 2023
b46fdb3
Address feedback
mdh1418 Mar 15, 2023
5761f4c
Address more feedback
mdh1418 Mar 16, 2023
a2d0360
Add various fixes and make bundle_path a local variable
mdh1418 Mar 16, 2023
5c7bec8
Reintroduce load aot data hook in autoinit with guard
mdh1418 Mar 16, 2023
1af3bd9
Fix closing tag
mdh1418 Mar 16, 2023
e41c3d3
Include guard library-builder.h
mdh1418 Mar 16, 2023
f87980b
Fix typo
mdh1418 Mar 16, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/mono/msbuild/android/build/AndroidApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
<MonoAOTCompilerDefaultAotArguments Include="static" />
<MonoAOTCompilerDefaultAotArguments Include="dwarfdebug" />
<MonoAOTCompilerDefaultAotArguments Condition="'$(_IsLibraryMode)' == 'true'" Include="direct-icalls" />
<MonoAOTCompilerDefaultAotArguments Condition="'$(_IsLibraryMode)' == 'true' and $(CustomRuntimeInitCallback) == ''" Include="runtime-init-callback" />
lateralusX marked this conversation as resolved.
Show resolved Hide resolved
<MonoAOTCompilerDefaultAotArguments Condition="'$(_IsLibraryMode)' == 'true' and $(CustomRuntimeInitCallback) != ''" Include="runtime-init-callback=$(CustomRuntimeInitCallback)" />

<MonoAOTCompilerDefaultAotArguments Include="nimt-trampolines=2000" />
<MonoAOTCompilerDefaultAotArguments Include="ntrampolines=10000" />
Expand Down
7 changes: 5 additions & 2 deletions 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 @@ -20,12 +22,13 @@
ExtraLinkerArguments="@(_ExtraLinkerArgs)"
ExtraSources="@(_ExtraLibrarySources)"
IsSharedLibrary="$(_IsSharedLibrary)"
Name="$(AssemblyName)"
MonoRuntimeHeaders="$(_MonoHeaderPath)"
Name="$(AssemblyName)"
OutputDirectory="$(BundleDir)"
RuntimeIdentifier="$(RuntimeIdentifier)"
RuntimeLibraries="@(_RuntimeLibraries)"
TargetOS="$(TargetOS)">
TargetOS="$(TargetOS)"
UsesCustomRuntimeInitCallback="$(_UsesCustomRuntimeInitCallback)">
<Output TaskParameter="OutputPath" PropertyName="LibraryOutputPath" />
</LibraryBuilderTask>
</Target>
Expand Down
102 changes: 101 additions & 1 deletion 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; }
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved

/// <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; }
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved

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);");
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
}
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};");
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
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*));");
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
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 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
1 change: 1 addition & 0 deletions src/tasks/LibraryBuilder/Templates/CMakeLists.txt.template
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ set(DOTNET_AOT_OBJECTS
set(DOTNET_EXTRA_SOURCES
%ExtraSources%
assembly_list.c
autoinit.c
)

include_directories("%MonoInclude%")
Expand Down
162 changes: 162 additions & 0 deletions src/tasks/LibraryBuilder/Templates/autoinit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/system_properties.h>
#include <unistd.h>

#include <mono/jit/jit.h>
#include <mono/jit/mono-private-unstable.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/mono-debug.h>

static char *bundle_path;

void register_aot_modules (void);
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
lateralusX marked this conversation as resolved.
Show resolved Hide resolved
char *monoeg_g_getenv (const char *variable);

static void
cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data)
{
free (args);
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
free (user_data);
}

static void
initialize_runtimeconfig ()
{
%RUNTIME_CONFIG%
}

static void
initialize_appctx_env_variables ()
{
%APPCTX_ENV_VARIABLES%
}

static MonoAssembly*
mono_load_assembly (const char *name, const char *culture)
{
char filename [1024];
char path [1024];
int res;

int len = strlen (name);
int has_extension = len > 3 && name [len - 4] == '.' && (!strcmp ("exe", name + (len - 3)) || !strcmp ("dll", name + (len - 3)));

// add extensions if required.
strlcpy (filename, name, sizeof (filename));
if (!has_extension) {
strlcat (filename, ".dll", sizeof (filename));
}

if (culture && strcmp (culture, ""))
res = snprintf (path, sizeof (path) - 1, "%s/%s/%s", bundle_path, culture, filename);
else
res = snprintf (path, sizeof (path) - 1, "%s/%s", bundle_path, filename);
assert (res > 0);

struct stat buffer;
if (stat (path, &buffer) == 0) {
MonoAssembly *assembly = mono_assembly_open (path, NULL);
assert (assembly);
return assembly;
}
return NULL;
}

static MonoAssembly*
mono_assembly_preload_hook (MonoAssemblyName *aname, char **assemblies_path, void* user_data)
{
const char *name = mono_assembly_name_get_name (aname);
const char *culture = mono_assembly_name_get_culture (aname);
return mono_load_assembly (name, culture);
}

static unsigned char *
load_aot_data (MonoAssembly *assembly, int size, void *user_data, void **out_handle)
{
*out_handle = NULL;

char path [1024];
int res;

MonoAssemblyName *assembly_name = mono_assembly_get_name (assembly);
const char *aname = mono_assembly_name_get_name (assembly_name);

res = snprintf (path, sizeof (path) - 1, "%s/%s.aotdata", bundle_path, aname);
assert (res > 0);

int fd = open (path, O_RDONLY);
if (fd < 0) {
return NULL;
}

void *ptr = mmap (NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
if (ptr == MAP_FAILED) {
close (fd);
return NULL;
}

close (fd);
*out_handle = ptr;
return (unsigned char *) ptr;
}

static void
free_aot_data (MonoAssembly *assembly, int size, void *user_data, void *handle)
{
munmap (handle, size);
}

void
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
runtime_init_callback ()
{
initialize_runtimeconfig ();

initialize_appctx_env_variables ();

register_aot_modules ();

// register all bundled modules

mono_set_assemblies_path ((bundle_path && bundle_path[0] != '\0') ? bundle_path : "./");

mono_jit_set_aot_only (true);

mono_install_assembly_preload_hook (mono_assembly_preload_hook, NULL);

// TODO test debug scenario
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
#if DEBUG_ENABLED
bool wait_for_debugger = false;
mono_debug_init (MONO_DEBUG_FORMAT_MONO);
if (wait_for_debugger) {
char* options[] = { "--debugger-agent=transport=dt_socket,server=y,address=0.0.0.0:55555" };
mono_jit_parse_options (1, options);
}
#endif

mono_install_load_aot_data_hook (load_aot_data, free_aot_data, NULL);

mono_set_signal_chaining (true);

mono_jit_init ("mono.self.contained.library"); // Pass in via LibraryBuilder?

%ASSEMBLIES_LOADER%
}

void
init_mono_runtime ()
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
{
bundle_path = monoeg_g_getenv("%ASSETS_PATH%");
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved
mono_set_runtime_init_callback (&runtime_init_callback);
}

void __attribute__((constructor))
lateralusX marked this conversation as resolved.
Show resolved Hide resolved
autoinit ()
{
init_mono_runtime ();
}