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

[wasm][wasi] Allow to build wasi in library mode #102806

Merged
merged 16 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
1 change: 1 addition & 0 deletions eng/testing/tests.wasi.targets
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<WasmSingleFileBundle Condition="'$(WasmSingleFileBundle)' == ''">false</WasmSingleFileBundle>
<WasmMainAssemblyFileName Condition="'$(WasmMainAssemblyFileName)' == ''">WasmTestRunner.dll</WasmMainAssemblyFileName>
<IsLibraryTest Condition="'$(OutputType)' == 'Library'">true</IsLibraryTest>
mkhamoyan marked this conversation as resolved.
Show resolved Hide resolved

<InstallWasmtimeForTests Condition="'$(InstallWasmtimeForTests)' == '' and
('$(ContinuousIntegrationBuild)' != 'true' or Exists('/.dockerenv'))"
Expand Down
1 change: 1 addition & 0 deletions src/mono/browser/runtime/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ MonoAssembly *mono_wasm_assembly_load (const char *name);
MonoClass *mono_wasm_assembly_find_class (MonoAssembly *assembly, const char *namespace, const char *name);
MonoMethod *mono_wasm_assembly_find_method (MonoClass *klass, const char *name, int arguments);
void mono_wasm_marshal_get_managed_wrapper (const char* assemblyName, const char* typeName, const char* methodName, int num_params);
int initialize_runtime ();

#endif
6 changes: 3 additions & 3 deletions src/mono/sample/wasi/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
TODOWASI - - tcplisten localhost:64000 - - env DEBUGGER_FD=4
-->
<Exec WorkingDirectory="bin/wasi-wasm/AppBundle"
Condition="'$(WasmBuildNative)' != 'true'"
Condition="'$(WasmBuildNative)' != 'true' and '$(OutputType)' != 'Library'"
mkhamoyan marked this conversation as resolved.
Show resolved Hide resolved
Command="$(WasmtimeDir)wasmtime$(_ExeExt) $(MONO_LOG_LEVEL) --dir . dotnet.wasm $(_SampleProjectName)" IgnoreExitCode="true" />
<Exec WorkingDirectory="bin/wasi-wasm/AppBundle"
Condition="'$(WasmBuildNative)' == 'true' and '$(WasmSingleFileBundle)' != 'true'"
Condition="'$(WasmBuildNative)' == 'true' and '$(WasmSingleFileBundle)' != 'true' and '$(OutputType)' != 'Library'"
Command="$(WasmtimeDir)wasmtime$(_ExeExt) $(MONO_LOG_LEVEL) --dir . dotnet.wasm" IgnoreExitCode="true" />
<Exec WorkingDirectory="bin/wasi-wasm/AppBundle"
Condition="'$(WasmSingleFileBundle)' == 'true'"
Condition="'$(WasmSingleFileBundle)' == 'true' and '$(OutputType)' != 'Library'"
Command="$(WasmtimeDir)wasmtime$(_ExeExt) $(MONO_LOG_LEVEL) $([System.IO.Path]::ChangeExtension($(_SampleAssembly), '.wasm'))" IgnoreExitCode="true" />
</Target>

Expand Down
15 changes: 11 additions & 4 deletions src/mono/sample/wasi/native/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,17 @@ public static int MyExport(int number)
[DllImport("*", EntryPoint = "UnmanagedFunc")]
public static extern void MyImport(); // calls ManagedFunc aka MyExport

public unsafe static int Main(string[] args)
// public unsafe static int Main(string[] args)
// {
// Console.WriteLine($"main: {args.Length}");
// MyImport();
// return 0;
// }

[UnmanagedCallersOnly(EntryPoint = "MyCallback")]
public static int MyCallback()
{
Console.WriteLine($"main: {args.Length}");
MyImport();
return 0;
Console.WriteLine("WASM Library MyCallback is called");
return 100;
}
}
5 changes: 5 additions & 0 deletions src/mono/sample/wasi/native/Wasi.Native.Sample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
<WasmNativeStrip>false</WasmNativeStrip>
<IsBrowserWasmProject>false</IsBrowserWasmProject>
<WasmSingleFileBundle>true</WasmSingleFileBundle>
<OutputType>Library</OutputType>
<!-- This is needed for ReferenceCopyLocalPaths to include RuntimePackAsset-->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<!-- This is needed so it will not complain about WasmAssembliesToBundle is empty -->
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
mkhamoyan marked this conversation as resolved.
Show resolved Hide resolved
</PropertyGroup>

<ItemGroup>
Expand Down
10 changes: 10 additions & 0 deletions src/mono/sample/wasi/native/runtimeconfig.template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"wasmHostProperties": {
"perHostConfig": [
{
"name": "wasmtime",
"Host": "wasmtime"
}
]
}
}
1 change: 1 addition & 0 deletions src/mono/wasi/build/WasiApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@
<_WasmCommonCFlags Condition="'$(InvariantGlobalization)' == 'true'" Include="-DINVARIANT_GLOBALIZATION=1" />
<_WasmCommonCFlags Condition="'$(InvariantTimezone)' == 'true'" Include="-DINVARIANT_TIMEZONE=1" />
<_WasmCommonCFlags Condition="'$(WasmLinkIcalls)' == 'true'" Include="-DLINK_ICALLS=1" />
<_WasmCommonCFlags Condition="'$(OutputType)' == 'Library' and '$(IsLibraryTest)' != 'true'" Include="-DWASM_LIBRARY_MODE=1" />
<_WasiClangCFlags Include="@(_WasmCommonCFlags)" />

<_WasiClangCFlags Include="&quot;-I%(_WasmCommonIncludePaths.Identity)&quot;" />
Expand Down
39 changes: 36 additions & 3 deletions src/mono/wasi/runtime/main.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <string.h>
#include <stdbool.h>
#include <string.h>
#include <driver.h>
#include <mono/metadata/assembly.h>

Expand All @@ -10,7 +11,31 @@ const char* dotnet_wasi_getentrypointassemblyname();
WASI_AFTER_RUNTIME_LOADED_DECLARATIONS
#endif

int main(int argc, char * argv[]) {
#ifdef WASM_LIBRARY_MODE
// _initialize is a function generated by the WASI SDK libc that calls the LLVM synthesized __wasm_call_ctors function for reactor components:
// https://github.com/WebAssembly/wasi-libc/blob/9f51a7102085ec6a6ced5778f0864c9af9f50000/libc-bottom-half/crt/crt1-reactor.c#L7-L27
// We define and call it for WASM_LIBRARY_MODE and TARGET_WASI to call all the global c++ static constructors. This ensures the runtime is initialized
// when calling into WebAssembly Component Model components.
extern void _initialize();

// CustomNativeMain programs are built using the same libbootstrapperdll as WASM_LIBRARY_MODE but wasi-libc will not provide an _initialize implementation,
// so create a dummy one here and make it weak to allow wasi-libc to provide the real implementation for WASI reactor components.
__attribute__((weak)) void _initialize()
{
mkhamoyan marked this conversation as resolved.
Show resolved Hide resolved
}

static bool runtime_initialized = false;

#endif

int initialize_runtime()
{
#if defined(WASM_LIBRARY_MODE)
if (runtime_initialized)
return 0;
_initialize();
runtime_initialized = true;
#endif
mkhamoyan marked this conversation as resolved.
Show resolved Hide resolved

#ifndef WASM_SINGLE_FILE
mono_set_assemblies_path("managed");
Expand All @@ -21,7 +46,14 @@ int main(int argc, char * argv[]) {
// This is supplied from the MSBuild itemgroup @(WasiAfterRuntimeLoaded)
WASI_AFTER_RUNTIME_LOADED_CALLS
#endif

return 0;
}

#ifndef WASM_LIBRARY_MODE
int main(int argc, char * argv[]) {
int initval = initialize_runtime();
if (initval != 0)
return initval;
int arg_ofs = 0;
#ifdef WASM_SINGLE_FILE
/*
Expand Down Expand Up @@ -71,3 +103,4 @@ int main(int argc, char * argv[]) {
}
return ret < 0 ? -ret : ret;
}
#endif
9 changes: 4 additions & 5 deletions src/mono/wasm/build/WasmApp.Common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@
</WasmLinkDotNetDependsOn>

<WasmDedup Condition="'$(WasmDedup)' == ''">true</WasmDedup>
<IsWasiProject Condition="'$(IsWasiProject)' == '' and '$(RuntimeIdentifier)' == 'wasi-wasm' and '$(OutputType)' != 'Library'">true</IsWasiProject>
<IsBrowserWasmProject Condition="'$(IsBrowserWasmProject)' == '' and '$(RuntimeIdentifier)' == 'browser-wasm' and '$(OutputType)' != 'Library'">true</IsBrowserWasmProject>
<IsWasiProject Condition="'$(IsWasiProject)' == '' and '$(RuntimeIdentifier)' == 'wasi-wasm'">true</IsWasiProject>
<IsBrowserWasmProject Condition="'$(IsBrowserWasmProject)' == '' and '$(RuntimeIdentifier)' == 'browser-wasm'">true</IsBrowserWasmProject>
<IsWasmProject Condition="'$(IsWasmProject)' == '' and ('$(IsWasiProject)' == 'true' or '$(IsBrowserWasmProject)' == 'true')">true</IsWasmProject>
<WasmBuildAppAfterThisTarget Condition="'$(WasmBuildAppAfterThisTarget)' == '' and '$(DisableAutoWasmBuildApp)' != 'true'">Build</WasmBuildAppAfterThisTarget>

Expand All @@ -173,8 +173,7 @@
<EnableDefaultWasmAssembliesToBundle Condition="'$(EnableDefaultWasmAssembliesToBundle)' == ''">true</EnableDefaultWasmAssembliesToBundle>
<!-- VS uses DeployOnBuild, and sdk sets _IsPublishing -->
<WasmBuildOnlyAfterPublish Condition="'$(WasmBuildOnlyAfterPublish)' == '' and ('$(DeployOnBuild)' == 'true' or '$(_IsPublishing)' == 'true')">true</WasmBuildOnlyAfterPublish>
<WasmGenerateAppBundle Condition="'$(WasmGenerateAppBundle)' == '' and '$(OutputType)' != 'Library'">true</WasmGenerateAppBundle>
<WasmGenerateAppBundle Condition="'$(WasmGenerateAppBundle)' == ''">false</WasmGenerateAppBundle>
<WasmGenerateAppBundle Condition="'$(WasmGenerateAppBundle)' == ''">true</WasmGenerateAppBundle>
mkhamoyan marked this conversation as resolved.
Show resolved Hide resolved

<!-- FIXME: can't set to true because
/workspaces/runtime/.dotnet/sdk/7.0.100-rc.1.22431.12/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(135,5): error NETSDK1084: There is no application host available for the specified RuntimeIdentifier 'wasi-wasm'.
Expand Down Expand Up @@ -346,7 +345,7 @@

<Target Name="_WasmGetRuntimeConfigPath">
<PropertyGroup>
<_MainAssemblyPath Condition="'%(WasmAssembliesToBundle.FileName)' == $(AssemblyName) and '%(WasmAssembliesToBundle.Extension)' == '.dll' and $(WasmGenerateAppBundle) == 'true'">%(WasmAssembliesToBundle.Identity)</_MainAssemblyPath>
<_MainAssemblyPath Condition="'%(WasmAssembliesToBundle.FileName)' == '$(AssemblyName)' and '%(WasmAssembliesToBundle.Extension)' == '.dll' and $(WasmGenerateAppBundle) == 'true'">%(WasmAssembliesToBundle.Identity)</_MainAssemblyPath>
<_WasmRuntimeConfigFilePath Condition="'$(_WasmRuntimeConfigFilePath)' == '' and $(_MainAssemblyPath) != ''">$([System.IO.Path]::ChangeExtension($(_MainAssemblyPath), '.runtimeconfig.json'))</_WasmRuntimeConfigFilePath>
<_ParsedRuntimeConfigFilePath Condition="'$(_WasmRuntimeConfigFilePath)' != ''">$([System.IO.Path]::GetDirectoryName($(_WasmRuntimeConfigFilePath)))\runtimeconfig.bin</_ParsedRuntimeConfigFilePath>
</PropertyGroup>
Expand Down
7 changes: 7 additions & 0 deletions src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,13 @@ private void EmitNativeToInterp(StreamWriter w, List<PInvokeCallback> callbacks)
if (!is_void)
sb.Append($" {MapType(method.ReturnType)} res;\n");

if (HasAttribute(method, "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute"))
{
sb.Append($" #if defined(WASM_LIBRARY_MODE) \n");
maraf marked this conversation as resolved.
Show resolved Hide resolved
sb.Append($" initialize_runtime(); \n");
sb.Append($" #endif\n");
}

// In case when null force interpreter to initialize the pointers
sb.Append($" if (!(WasmInterpEntrySig_{cb_index})wasm_native_to_interp_ftndescs [{cb_index}].func) {{\n");
var assemblyFullName = cb.Method.DeclaringType == null ? "" : cb.Method.DeclaringType.Assembly.FullName;
Expand Down
Loading