diff --git a/Directory.Build.props b/Directory.Build.props
index eea40af21a60b6..2da3b59909e3a5 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -36,6 +36,7 @@
s390x
ppc64le
wasm
+ wasm
x64
x64
$(TargetArchitecture)
@@ -129,6 +130,8 @@
$([MSBuild]::NormalizePath('$(TestExclusionListTasksDir)', 'TestExclusionListTasks.dll'))
$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'coreclr', '$(TargetOS).$(TargetArchitecture).$(Configuration)'))
$(CoreCLRToolPath)
+
+ $([MSBuild]::NormalizeDirectory($(ArtifactsObjDir), 'wasmtime'))
diff --git a/eng/build.ps1 b/eng/build.ps1
index 9382d460248aff..e3e009d12da47d 100644
--- a/eng/build.ps1
+++ b/eng/build.ps1
@@ -241,6 +241,10 @@ if ($PSBoundParameters.ContainsKey('os') -and $PSBoundParameters['os'] -eq "Brow
# make sure it is capitalized
$PSBoundParameters['os'] = "Browser"
}
+if ($PSBoundParameters.ContainsKey('os') -and $PSBoundParameters['os'] -eq "wasi") {
+ # make sure it is not capitalized
+ $PSBoundParameters['os'] = "wasi"
+}
foreach ($argument in $PSBoundParameters.Keys)
{
diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake
index 51e8384413750f..2a72b492fc30f1 100644
--- a/eng/native/configurecompiler.cmake
+++ b/eng/native/configurecompiler.cmake
@@ -168,7 +168,7 @@ elseif (CLR_CMAKE_HOST_UNIX)
endif ()
endif(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG OR UPPERCASE_CMAKE_BUILD_TYPE STREQUAL CHECKED)
- if(CLR_CMAKE_HOST_BROWSER)
+ if(CLR_CMAKE_HOST_BROWSER OR CLR_CMAKE_HOST_WASI)
# The emscripten build has additional warnings so -Werror breaks
add_compile_options(-Wno-unused-parameter)
add_compile_options(-Wno-alloca)
@@ -390,7 +390,7 @@ if (CLR_CMAKE_HOST_UNIX)
add_definitions(-DLSE_INSTRUCTIONS_ENABLED_BY_DEFAULT)
add_compile_options(-mcpu=apple-m1)
endif(CLR_CMAKE_HOST_UNIX_ARM64)
- elseif(NOT CLR_CMAKE_HOST_BROWSER)
+ elseif(NOT CLR_CMAKE_HOST_BROWSER AND NOT CLR_CMAKE_HOST_WASI)
check_c_compiler_flag(-fstack-protector-strong COMPILER_SUPPORTS_F_STACK_PROTECTOR_STRONG)
if (COMPILER_SUPPORTS_F_STACK_PROTECTOR_STRONG)
add_compile_options(-fstack-protector-strong)
@@ -795,7 +795,7 @@ if (CLR_CMAKE_HOST_WIN32)
message(FATAL_ERROR "MC not found")
endif()
-elseif (NOT CLR_CMAKE_HOST_BROWSER)
+elseif (NOT CLR_CMAKE_HOST_BROWSER AND NOT CLR_CMAKE_HOST_WASI)
# This is a workaround for upstream issue: https://gitlab.kitware.com/cmake/cmake/-/issues/22995.
#
# In Clang.cmake, the decision to use single or double hyphen for target and gcc-toolchain
diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake
index c849c592174af3..b064079402eb45 100644
--- a/eng/native/configureplatform.cmake
+++ b/eng/native/configureplatform.cmake
@@ -214,9 +214,9 @@ if(CLR_CMAKE_HOST_OS STREQUAL Emscripten)
set(CLR_CMAKE_HOST_BROWSER 1)
endif(CLR_CMAKE_HOST_OS STREQUAL Emscripten)
-if(CLR_CMAKE_TARGET_OS STREQUAL Wasi)
+if(CLR_CMAKE_TARGET_OS STREQUAL WASI)
set(CLR_CMAKE_HOST_WASI 1)
-endif(CLR_CMAKE_TARGET_OS STREQUAL Wasi)
+endif(CLR_CMAKE_TARGET_OS STREQUAL WASI)
#--------------------------------------------
# This repo builds two set of binaries
@@ -417,9 +417,9 @@ if(CLR_CMAKE_TARGET_OS STREQUAL Emscripten)
set(CLR_CMAKE_TARGET_BROWSER 1)
endif(CLR_CMAKE_TARGET_OS STREQUAL Emscripten)
-if(CLR_CMAKE_TARGET_OS STREQUAL Wasi)
+if(CLR_CMAKE_TARGET_OS STREQUAL WASI)
set(CLR_CMAKE_TARGET_WASI 1)
-endif(CLR_CMAKE_TARGET_OS STREQUAL Wasi)
+endif(CLR_CMAKE_TARGET_OS STREQUAL WASI)
if(CLR_CMAKE_TARGET_UNIX)
if(CLR_CMAKE_TARGET_ARCH STREQUAL x64)
@@ -454,7 +454,7 @@ else()
endif(CLR_CMAKE_TARGET_UNIX)
# check if host & target os/arch combination are valid
-if (NOT (CLR_CMAKE_TARGET_OS STREQUAL CLR_CMAKE_HOST_OS))
+if (NOT (CLR_CMAKE_TARGET_OS STREQUAL CLR_CMAKE_HOST_OS) AND NOT CLR_CMAKE_TARGET_WASI)
if(NOT (CLR_CMAKE_HOST_OS STREQUAL windows))
message(FATAL_ERROR "Invalid host and target os/arch combination. Host OS: ${CLR_CMAKE_HOST_OS}")
endif()
@@ -466,7 +466,7 @@ if (NOT (CLR_CMAKE_TARGET_OS STREQUAL CLR_CMAKE_HOST_OS))
endif()
endif()
-if(NOT CLR_CMAKE_TARGET_BROWSER)
+if(NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
# The default linker on Solaris also does not support PIE.
if(NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_SUNOS AND NOT CLR_CMAKE_TARGET_OSX AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_HOST_TVOS AND NOT CLR_CMAKE_HOST_IOS AND NOT MSVC)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie")
diff --git a/eng/native/configuretools.cmake b/eng/native/configuretools.cmake
index 07a3bbfafe4dd9..1f800b0f897895 100644
--- a/eng/native/configuretools.cmake
+++ b/eng/native/configuretools.cmake
@@ -6,7 +6,7 @@ if (CMAKE_C_COMPILER MATCHES "-?[0-9]+(\.[0-9]+)?$")
set(CLR_CMAKE_COMPILER_FILE_NAME_VERSION "${CMAKE_MATCH_0}")
endif()
-if(NOT WIN32 AND NOT CLR_CMAKE_TARGET_BROWSER)
+if(NOT WIN32 AND NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
if(APPLE)
set(TOOLSET_PREFIX "")
diff --git a/eng/native/gen-buildsys.cmd b/eng/native/gen-buildsys.cmd
index b97b8125e0f8c0..fb70a4e0c29bf7 100644
--- a/eng/native/gen-buildsys.cmd
+++ b/eng/native/gen-buildsys.cmd
@@ -48,21 +48,34 @@ if /i "%__Arch%" == "wasm" (
)
if /i "%__Os%" == "Browser" (
if "%EMSDK_PATH%" == "" (
- if not exist "%__repoRoot%src\mono\wasm\emsdk" (
+ if not exist "%__repoRoot%\src\mono\wasm\emsdk" (
echo Error: Should set EMSDK_PATH environment variable pointing to emsdk root.
exit /B 1
)
- set EMSDK_PATH=%__repoRoot%src\mono\wasm\emsdk
- set EMSDK_PATH=!EMSDK_PATH:\=/!
+ set EMSDK_PATH=%__repoRoot%\src\mono\wasm\emsdk
)
+ :: replace backslash with forward slash and append last slash
+ set "EMSDK_PATH=!EMSDK_PATH:\=/!"
+ if not "!EMSDK_PATH:~-1!" == "/" set "EMSDK_PATH=!EMSDK_PATH!/"
set __ExtraCmakeParams=%__ExtraCmakeParams% "-DCMAKE_TOOLCHAIN_FILE=!EMSDK_PATH!/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake"
set __UseEmcmake=1
)
if /i "%__Os%" == "wasi" (
- echo Error: WASI build not implemented on Windows yet
- exit /B 1
+ if "%WASI_SDK_PATH%" == "" (
+ if not exist "%__repoRoot%\src\mono\wasi\wasi-sdk" (
+ echo Error: Should set WASI_SDK_PATH environment variable pointing to emsdk root.
+ exit /B 1
+ )
+
+ set WASI_SDK_PATH=%__repoRoot%src\mono\wasi\wasi-sdk
+ )
+ :: replace backslash with forward slash and append last slash
+ set "WASI_SDK_PATH=!WASI_SDK_PATH:\=/!"
+ if not "!WASI_SDK_PATH:~-1!" == "/" set "WASI_SDK_PATH=!WASI_SDK_PATH!/"
+ set __CmakeGenerator=Ninja
+ set __ExtraCmakeParams=%__ExtraCmakeParams% -DCLR_CMAKE_TARGET_OS=WASI -DCLR_CMAKE_TARGET_ARCH=wasm "-DWASI_SDK_PREFIX=!WASI_SDK_PATH!" "-DCMAKE_TOOLCHAIN_FILE=!WASI_SDK_PATH!/share/cmake/wasi-sdk.cmake" "-DCMAKE_SYSROOT=!WASI_SDK_PATH!/share/wasi-sysroot"
)
) else (
set __ExtraCmakeParams=%__ExtraCmakeParams% "-DCMAKE_SYSTEM_VERSION=10.0"
diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml
index c3ef697a85da07..a876f91e81b7e7 100644
--- a/eng/pipelines/common/platform-matrix.yml
+++ b/eng/pipelines/common/platform-matrix.yml
@@ -358,6 +358,27 @@ jobs:
crossBuild: true
${{ insert }}: ${{ parameters.jobParameters }}
+# WASI WebAssembly
+
+- ${{ if containsValue(parameters.platforms, 'wasi_wasm') }}:
+ - template: xplat-setup.yml
+ parameters:
+ jobTemplate: ${{ parameters.jobTemplate }}
+ helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }}
+ variables: ${{ parameters.variables }}
+ osGroup: wasi
+ archType: wasm
+ targetRid: wasi-wasm
+ platform: wasi_wasm
+ shouldContinueOnError: ${{ parameters.shouldContinueOnError }}
+ container: wasi_wasm
+ jobParameters:
+ hostedOs: Linux
+ runtimeFlavor: ${{ parameters.runtimeFlavor }}
+ stagedBuild: ${{ parameters.stagedBuild }}
+ buildConfig: ${{ parameters.buildConfig }}
+ ${{ insert }}: ${{ parameters.jobParameters }}
+
# Browser WebAssembly
- ${{ if containsValue(parameters.platforms, 'Browser_wasm') }}:
diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml
index 6371f176d872d0..9de181cce75421 100644
--- a/eng/pipelines/common/templates/pipeline-with-resources.yml
+++ b/eng/pipelines/common/templates/pipeline-with-resources.yml
@@ -60,6 +60,9 @@ resources:
- container: Browser_wasm
image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-webassembly
+ - container: wasi_wasm
+ image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-webassembly
+
- container: FreeBSD_x64
image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-freebsd-12
env:
diff --git a/eng/pipelines/common/templates/wasi-build-only.yml b/eng/pipelines/common/templates/wasi-build-only.yml
new file mode 100644
index 00000000000000..e161b02b1270c3
--- /dev/null
+++ b/eng/pipelines/common/templates/wasi-build-only.yml
@@ -0,0 +1,49 @@
+parameters:
+ alwaysRun: false
+ extraBuildArgs: ''
+ isExtraPlatformsBuild: false
+ nameSuffix: ''
+ platforms: []
+
+jobs:
+
+#
+# Build for WASI/wasm and test it
+#
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
+ buildConfig: Release
+ runtimeFlavor: mono
+ platforms: ${{ parameters.platforms }}
+ variables:
+ # map dependencies variables to local variables
+ - name: alwaysRunVar
+ value: ${{ parameters.alwaysRun }}
+ - name: shouldRunOnDefaultPipelines
+ value: $[
+ or(
+ eq(variables['wasmDarcDependenciesChanged'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true),
+ and(
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_wasm.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_non_runtimetests.containsChange'], true)),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_wasm_libraries.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_mono_excluding_wasm.containsChange'], true))
+ ]
+ jobParameters:
+ isExtraPlatforms: ${{ parameters.isExtraPlatformsBuild }}
+ testGroup: innerloop
+ nameSuffix: ${{ parameters.nameSuffix }}_BuildOnly
+ buildArgs: -s mono+libs+host -c $(_BuildConfig) /p:ArchiveTests=true ${{ parameters.extraBuildArgs }}
+ timeoutInMinutes: 240
+ # if !alwaysRun, then:
+ # if this is runtime-wasm (isWasmOnlyBuild):
+ # - then run only if it would not have run on default pipelines (based
+ # on path changes)
+ # - else run based on path changes
+ condition: >-
+ or(
+ eq(variables['alwaysRunVar'], true),
+ eq(variables['isDefaultPipeline'], variables['shouldRunOnDefaultPipelines']))
diff --git a/eng/pipelines/common/templates/wasm-library-tests.yml b/eng/pipelines/common/templates/wasm-library-tests.yml
index caf4a09b31eb19..dfc447572863f0 100644
--- a/eng/pipelines/common/templates/wasm-library-tests.yml
+++ b/eng/pipelines/common/templates/wasm-library-tests.yml
@@ -71,16 +71,8 @@ jobs:
eq(variables['alwaysRunVar'], true),
eq(variables['isDefaultPipeline'], variables['shouldRunOnDefaultPipelines']))
# extra steps, run tests
- extraStepsTemplate: /eng/pipelines/common/templates/additional-steps-then-helix.yml
+ extraStepsTemplate: /eng/pipelines/libraries/helix.yml
extraStepsParameters:
- additionalSteps:
- - ${{ if eq(parameters.buildAndRunWasi, true) }}:
- - script: >-
- make -C src/mono/wasi provision-deps all &&
- make -C src/mono/wasi/sample/console run
- name: build_wasi
- displayName: Build WASI, and run a sample
-
creator: dotnet-bot
testRunNamePrefixSuffix: Mono_$(_BuildConfig)
extraHelixArguments: /p:BrowserHost=$(_hostedOs) $(_wasmRunSmokeTestsOnlyArg) ${{ parameters.extraHelixArgs }}
diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml
index 0a46eb3bd6ed6f..043d5fb251cf4f 100644
--- a/eng/pipelines/libraries/helix-queues-setup.yml
+++ b/eng/pipelines/libraries/helix-queues-setup.yml
@@ -187,8 +187,8 @@ jobs:
- ${{ if eq(parameters.platform, 'windows_arm64') }}:
- Windows.11.Arm64.Open
- # Browser WebAssembly
- - ${{ if eq(parameters.platform, 'Browser_wasm') }}:
+ # Browser/WASI WebAssembly
+ - ${{ if in(parameters.platform, 'Browser_wasm', 'wasi_wasm') }}:
- Ubuntu.1804.Amd64.Open
# Browser WebAssembly Firefox
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index 56581e27013083..a899ac948f1a33 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -456,6 +456,13 @@ extends:
extraBuildArgs: /p:MonoWasmBuildVariant=perftrace
alwaysRun: ${{ variables.isRollingBuild }}
+ # BUILD ONLY - WASI/Wasm
+ - template: /eng/pipelines/common/templates/wasi-build-only.yml
+ parameters:
+ platforms:
+ - wasi_wasm
+ alwaysRun: ${{ variables.isRollingBuild }}
+
#
# iOS/tvOS devices - Full AOT + AggressiveTrimming to reduce size
# Build the whole product using Mono and run libraries tests
diff --git a/eng/targetingpacks.targets b/eng/targetingpacks.targets
index 1df3493b74c9f8..7474ec60b55696 100644
--- a/eng/targetingpacks.targets
+++ b/eng/targetingpacks.targets
@@ -45,7 +45,7 @@
RuntimeFrameworkName="$(LocalFrameworkOverrideName)"
LatestRuntimeFrameworkVersion="$(ProductVersion)"
RuntimePackNamePatterns="$(LocalFrameworkOverrideName).Runtime.Mono.**RID**"
- RuntimePackRuntimeIdentifiers="linux-arm;linux-arm64;linux-musl-arm64;linux-musl-x64;linux-x64;osx-x64;rhel.6-x64;win-arm;win-arm64;win-x64;win-x86;linux-musl-arm;osx-arm64;maccatalyst-x64;maccatalyst-arm64;linux-s390x;linux-bionic-arm;linux-bionic-arm64;linux-bionic-x64;linux-bionic-x86;browser-wasm;ios-arm64;ios-arm;iossimulator-arm64;iossimulator-x64;iossimulator-x86;tvos-arm64;tvossimulator-arm64;tvossimulator-x64;android-arm64;android-arm;android-x64;android-x86"
+ RuntimePackRuntimeIdentifiers="linux-arm;linux-arm64;linux-musl-arm64;linux-musl-x64;linux-x64;osx-x64;rhel.6-x64;win-arm;win-arm64;win-x64;win-x86;linux-musl-arm;osx-arm64;maccatalyst-x64;maccatalyst-arm64;linux-s390x;linux-bionic-arm;linux-bionic-arm64;linux-bionic-x64;linux-bionic-x86;browser-wasm;wasi-wasm;ios-arm64;ios-arm;iossimulator-arm64;iossimulator-x64;iossimulator-x86;tvos-arm64;tvossimulator-arm64;tvossimulator-x64;android-arm64;android-arm;android-x64;android-x86"
RuntimePackLabels="Mono"
Condition="'@(KnownRuntimePack)' == '' or !@(KnownRuntimePack->AnyHaveMetadataValue('TargetFramework', '$(NetCoreAppCurrent)'))"/>
+
+
diff --git a/eng/versioning.targets b/eng/versioning.targets
index 1e251f645b3272..96dab80373295c 100644
--- a/eng/versioning.targets
+++ b/eng/versioning.targets
@@ -65,6 +65,9 @@
true
+
+ true
+
@@ -78,6 +81,9 @@
+
+
+
diff --git a/src/libraries/System.Console/src/System.Console.csproj b/src/libraries/System.Console/src/System.Console.csproj
index 7892e19b467295..a93be382bf61b9 100644
--- a/src/libraries/System.Console/src/System.Console.csproj
+++ b/src/libraries/System.Console/src/System.Console.csproj
@@ -1,12 +1,14 @@
true
- $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-android;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)
+ $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-android;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)
$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))
SR.PlatformNotSupported_SystemConsole
+ $(DefineConstants);TARGET_BROWSER
+ $(DefineConstants);TARGET_WASI
@@ -47,7 +49,7 @@
Common\Interop\Android\Interop.Libraries.cs
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -158,6 +191,7 @@
+
diff --git a/src/libraries/System.Console/src/System/ConsolePal.Unix.ConsoleStream.cs b/src/libraries/System.Console/src/System/ConsolePal.Unix.ConsoleStream.cs
new file mode 100644
index 00000000000000..96eae08d1b5ea6
--- /dev/null
+++ b/src/libraries/System.Console/src/System/ConsolePal.Unix.ConsoleStream.cs
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.Win32.SafeHandles;
+using System.Diagnostics;
+using System.IO;
+
+namespace System
+{
+ internal static partial class ConsolePal
+ {
+ /// Provides a stream to use for Unix console input or output.
+ private sealed class UnixConsoleStream : ConsoleStream
+ {
+ /// The file descriptor for the opened file.
+ private readonly SafeFileHandle _handle;
+
+ private readonly bool _useReadLine;
+
+ /// Initialize the stream.
+ /// The file handle wrapped by this stream.
+ /// FileAccess.Read or FileAccess.Write.
+ /// Use ReadLine API for reading.
+ internal UnixConsoleStream(SafeFileHandle handle, FileAccess access, bool useReadLine = false)
+ : base(access)
+ {
+ Debug.Assert(handle != null, "Expected non-null console handle");
+ Debug.Assert(!handle.IsInvalid, "Expected valid console handle");
+ _handle = handle;
+ _useReadLine = useReadLine;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _handle.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ public override int Read(Span buffer) =>
+#if !TARGET_WASI
+ _useReadLine ?
+ ConsolePal.StdInReader.ReadLine(buffer) :
+#endif
+ ConsolePal.Read(_handle, buffer);
+
+ public override void Write(ReadOnlySpan buffer) =>
+ ConsolePal.Write(_handle, buffer);
+
+ public override void Flush()
+ {
+ if (_handle.IsClosed)
+ {
+ throw Error.GetFileNotOpen();
+ }
+ base.Flush();
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Console/src/System/ConsolePal.Unix.cs b/src/libraries/System.Console/src/System/ConsolePal.Unix.cs
index 922d1d670ed43d..fab69c58baa27a 100644
--- a/src/libraries/System.Console/src/System/ConsolePal.Unix.cs
+++ b/src/libraries/System.Console/src/System/ConsolePal.Unix.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Win32.SafeHandles;
-using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
@@ -1120,53 +1119,5 @@ internal static void WriteStdoutAnsiString(string? value, bool mayChangeCursorPo
Write(Interop.Sys.FileDescriptors.STDOUT_FILENO, data, mayChangeCursorPosition);
}
}
-
- /// Provides a stream to use for Unix console input or output.
- private sealed class UnixConsoleStream : ConsoleStream
- {
- /// The file descriptor for the opened file.
- private readonly SafeFileHandle _handle;
-
- private readonly bool _useReadLine;
-
- /// Initialize the stream.
- /// The file handle wrapped by this stream.
- /// FileAccess.Read or FileAccess.Write.
- /// Use ReadLine API for reading.
- internal UnixConsoleStream(SafeFileHandle handle, FileAccess access, bool useReadLine = false)
- : base(access)
- {
- Debug.Assert(handle != null, "Expected non-null console handle");
- Debug.Assert(!handle.IsInvalid, "Expected valid console handle");
- _handle = handle;
- _useReadLine = useReadLine;
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- _handle.Dispose();
- }
- base.Dispose(disposing);
- }
-
- public override int Read(Span buffer) =>
- _useReadLine ?
- ConsolePal.StdInReader.ReadLine(buffer) :
- ConsolePal.Read(_handle, buffer);
-
- public override void Write(ReadOnlySpan buffer) =>
- ConsolePal.Write(_handle, buffer);
-
- public override void Flush()
- {
- if (_handle.IsClosed)
- {
- throw Error.GetFileNotOpen();
- }
- base.Flush();
- }
- }
}
}
diff --git a/src/libraries/System.Console/src/System/ConsolePal.Wasi.cs b/src/libraries/System.Console/src/System/ConsolePal.Wasi.cs
new file mode 100644
index 00000000000000..22fb160f4c1814
--- /dev/null
+++ b/src/libraries/System.Console/src/System/ConsolePal.Wasi.cs
@@ -0,0 +1,333 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.Win32.SafeHandles;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Threading;
+#pragma warning disable IDE0060
+
+namespace System
+{
+ // Provides Unix-based support for System.Console.
+ //
+ // NOTE: The test class reflects over this class to run the tests due to limitations in
+ // the test infrastructure that prevent OS-specific builds of test binaries. If you
+ // change any of the class / struct / function names, parameters, etc then you need
+ // to also change the test class.
+ internal static partial class ConsolePal
+ {
+ // StdInReader is only used when input isn't redirected and we're working
+ // with an interactive terminal. In that case, performance isn't critical
+ // and we can use a smaller buffer to minimize working set.
+ // there is no dup on WASI
+ public static Stream OpenStandardInput()
+ {
+ return new UnixConsoleStream(Interop.CheckIo(Interop.Sys.FileDescriptors.STDIN_FILENO), FileAccess.Read,
+ useReadLine: !Console.IsInputRedirected);
+ }
+
+ public static Stream OpenStandardOutput()
+ {
+ return new UnixConsoleStream(Interop.CheckIo(Interop.Sys.FileDescriptors.STDOUT_FILENO), FileAccess.Write);
+ }
+
+ public static Stream OpenStandardError()
+ {
+ return new UnixConsoleStream(Interop.CheckIo(Interop.Sys.FileDescriptors.STDERR_FILENO), FileAccess.Write);
+ }
+
+ public static Encoding InputEncoding
+ {
+ get { return GetConsoleEncoding(); }
+ }
+
+ public static Encoding OutputEncoding
+ {
+ get { return GetConsoleEncoding(); }
+ }
+
+ internal static TextReader GetOrCreateReader()
+ {
+ Stream inputStream = OpenStandardInput();
+ return inputStream == Stream.Null ?
+ StreamReader.Null :
+ new StreamReader(
+ stream: inputStream,
+ encoding: Console.InputEncoding,
+ detectEncodingFromByteOrderMarks: false,
+ bufferSize: Console.ReadBufferSize,
+ leaveOpen: true);
+ }
+
+ public static bool KeyAvailable => false;
+
+ public static ConsoleKeyInfo ReadKey(bool intercept) => throw new PlatformNotSupportedException();
+
+ public static bool TreatControlCAsInput
+ {
+ get => throw new PlatformNotSupportedException();
+ set => throw new PlatformNotSupportedException();
+ }
+
+ public static ConsoleColor ForegroundColor
+ {
+ get => throw new PlatformNotSupportedException();
+ set => throw new PlatformNotSupportedException();
+ }
+ public static ConsoleColor BackgroundColor
+ {
+ get => throw new PlatformNotSupportedException();
+ set => throw new PlatformNotSupportedException();
+ }
+ public static void ResetColor() => throw new PlatformNotSupportedException();
+
+ public static bool NumberLock { get { throw new PlatformNotSupportedException(); } }
+
+ public static bool CapsLock { get { throw new PlatformNotSupportedException(); } }
+
+ public static int CursorSize
+ {
+ get { return 100; }
+ set { throw new PlatformNotSupportedException(); }
+ }
+
+
+ public static string Title
+ {
+ get { throw new PlatformNotSupportedException(); }
+ set => throw new PlatformNotSupportedException();
+ }
+
+ public static void Beep() => throw new PlatformNotSupportedException();
+
+ public static void Clear() => throw new PlatformNotSupportedException();
+ public static void SetCursorPosition(int left, int top) => throw new PlatformNotSupportedException();
+ public static bool IsInputRedirectedCore() => throw new PlatformNotSupportedException();
+ public static bool IsOutputRedirectedCore() => throw new PlatformNotSupportedException();
+ public static bool IsErrorRedirectedCore() => throw new PlatformNotSupportedException();
+
+ public static int BufferWidth
+ {
+ get { return WindowWidth; }
+ set { throw new PlatformNotSupportedException(); }
+ }
+
+ public static int BufferHeight
+ {
+ get { return WindowHeight; }
+ set { throw new PlatformNotSupportedException(); }
+ }
+
+ public static int LargestWindowWidth
+ {
+ get { return WindowWidth; }
+ }
+
+ public static int LargestWindowHeight
+ {
+ get { return WindowHeight; }
+ }
+
+ public static int WindowLeft
+ {
+ get { return 0; }
+ set { throw new PlatformNotSupportedException(); }
+ }
+
+ public static int WindowTop
+ {
+ get { return 0; }
+ set { throw new PlatformNotSupportedException(); }
+ }
+
+ public static int WindowWidth
+ {
+ get
+ {
+ GetWindowSize(out int width, out _);
+ return width;
+ }
+ set => SetWindowSize(value, WindowHeight);
+ }
+
+ public static int WindowHeight
+ {
+ get
+ {
+ GetWindowSize(out _, out int height);
+ return height;
+ }
+ set => SetWindowSize(WindowWidth, value);
+ }
+
+ private static void GetWindowSize(out int width, out int height)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static void SetWindowSize(int width, int height)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static bool CursorVisible
+ {
+ get { throw new PlatformNotSupportedException(); }
+ set
+ {
+ throw new PlatformNotSupportedException();
+ }
+ }
+
+ public static (int Left, int Top) GetCursorPosition()
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ /// Creates an encoding from the current environment.
+ /// The encoding.
+ private static Encoding GetConsoleEncoding()
+ {
+ Encoding? enc = EncodingHelper.GetEncodingFromCharset();
+ return enc != null ?
+ enc.RemovePreamble() :
+ Encoding.Default;
+ }
+
+#pragma warning disable IDE0060
+ public static void Beep(int frequency, int duration)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static void MoveBufferArea(int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight, int targetLeft, int targetTop)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static void MoveBufferArea(int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight, int targetLeft, int targetTop, char sourceChar, ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static void SetBufferSize(int width, int height)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static void SetConsoleInputEncoding(Encoding enc)
+ {
+ // No-op.
+ // There is no good way to set the terminal console encoding.
+ }
+
+ public static void SetConsoleOutputEncoding(Encoding enc)
+ {
+ // No-op.
+ // There is no good way to set the terminal console encoding.
+ }
+
+ public static void SetWindowPosition(int left, int top)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+#pragma warning restore IDE0060
+
+ internal static void EnsureConsoleInitialized()
+ {
+ }
+
+ /// Reads data from the file descriptor into the buffer.
+ /// The file descriptor.
+ /// The buffer to read into.
+ /// The number of bytes read, or an exception if there's an error.
+ private static unsafe int Read(SafeFileHandle fd, Span buffer)
+ {
+ fixed (byte* bufPtr = buffer)
+ {
+ int result = Interop.CheckIo(Interop.Sys.Read(fd, bufPtr, buffer.Length));
+ Debug.Assert(result <= buffer.Length);
+ return result;
+ }
+ }
+
+ /// Writes data from the buffer into the file descriptor.
+ /// The file descriptor.
+ /// The buffer from which to write data.
+ /// Writing this buffer may change the cursor position.
+ internal static unsafe void Write(SafeFileHandle fd, ReadOnlySpan buffer, bool mayChangeCursorPosition = true)
+ {
+ // Console initialization might emit data to stdout.
+ // In order to avoid splitting user data we need to
+ // complete it before any writes are performed.
+ EnsureConsoleInitialized();
+
+ fixed (byte* p = buffer)
+ {
+ byte* bufPtr = p;
+ int count = buffer.Length;
+ while (count > 0)
+ {
+ int bytesWritten = Interop.Sys.Write(fd, bufPtr, count);
+ if (bytesWritten < 0)
+ {
+ Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
+ if (errorInfo.Error == Interop.Error.EPIPE)
+ {
+ // Broken pipe... likely due to being redirected to a program
+ // that ended, so simply pretend we were successful.
+ return;
+ }
+ else if (errorInfo.Error == Interop.Error.EAGAIN) // aka EWOULDBLOCK
+ {
+ // May happen if the file handle is configured as non-blocking.
+ // In that case, we need to wait to be able to write and then
+ // try again. We poll, but don't actually care about the result,
+ // only the blocking behavior, and thus ignore any poll errors
+ // and loop around to do another write (which may correctly fail
+ // if something else has gone wrong).
+ Interop.Sys.Poll(fd, Interop.PollEvents.POLLOUT, Timeout.Infinite, out Interop.PollEvents triggered);
+ continue;
+ }
+ else
+ {
+ // Something else... fail.
+ throw Interop.GetExceptionForIoErrno(errorInfo);
+ }
+ }
+ count -= bytesWritten;
+ bufPtr += bytesWritten;
+ }
+ }
+ }
+
+ /// Writes a terminfo-based ANSI escape string to stdout.
+ /// The string to write.
+ /// Writing this value may change the cursor position.
+ internal static void WriteStdoutAnsiString(string? value, bool mayChangeCursorPosition = true)
+ {
+ if (string.IsNullOrEmpty(value))
+ return;
+
+ scoped Span data;
+ if (value.Length <= 256) // except for extremely rare cases, ANSI escape strings are very short
+ {
+ data = stackalloc byte[Encoding.UTF8.GetMaxByteCount(value.Length)];
+ int bytesToWrite = Encoding.UTF8.GetBytes(value, data);
+ data = data.Slice(0, bytesToWrite);
+ }
+ else
+ {
+ data = Encoding.UTF8.GetBytes(value);
+ }
+
+ lock (Console.Out) // synchronize with other writers
+ {
+ Write(Interop.Sys.FileDescriptors.STDOUT_FILENO, data, mayChangeCursorPosition);
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.IO.Compression/src/System.IO.Compression.csproj b/src/libraries/System.IO.Compression/src/System.IO.Compression.csproj
index 98cb4c50617afe..d05a1d7995875d 100644
--- a/src/libraries/System.IO.Compression/src/System.IO.Compression.csproj
+++ b/src/libraries/System.IO.Compression/src/System.IO.Compression.csproj
@@ -1,7 +1,7 @@
true
- $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)
+ $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)
@@ -50,7 +50,7 @@
Link="Common\Interop\Windows\Interop.Libraries.cs" />
-
+
- $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-freebsd;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-solaris;$(NetCoreAppCurrent)-android;$(NetCoreAppCurrent)
+ $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-freebsd;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-solaris;$(NetCoreAppCurrent)-android;$(NetCoreAppCurrent)
true
$(DefineConstants);HTTP_DLL
true
@@ -16,14 +16,15 @@
$(DefineConstants);TARGET_MACCATALYST
$(DefineConstants);TARGET_TVOS
$(DefineConstants);TARGET_BROWSER
+ $(DefineConstants);TARGET_WASI
$(MSBuildThisFileDirectory)ILLink\
-
-
+
+
diff --git a/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj b/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj
index b051d509fd60ac..8e47f09dd48582 100644
--- a/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj
+++ b/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj
@@ -2,7 +2,7 @@
true
false
- $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)
+ $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)
$(DefineConstants);SYSTEM_NET_PRIMITIVES_DLL
@@ -113,7 +113,7 @@
-
+
@@ -144,7 +144,7 @@
-
+
enable
true
true
- true
+ true
true
true
true
@@ -20,7 +20,7 @@
$(MSBuildThisFileDirectory)ILLink\
true
true
- true
+ true
$(DefineConstants);BIGENDIAN
@@ -2048,7 +2048,7 @@
-
+
Common\Interop\Unix\Interop.Errors.cs
@@ -2298,7 +2298,7 @@
-
+
@@ -2307,7 +2307,7 @@
-
+
@@ -2341,7 +2341,7 @@
-
+
@@ -2445,7 +2445,7 @@
-
+
@@ -2458,11 +2458,11 @@
-
+
-
+
@@ -2480,7 +2480,7 @@
-
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
index 2dc7015dda0a3f..b2c83e67dd4538 100644
--- a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs
@@ -12,7 +12,7 @@ namespace System
{
public static partial class AppContext
{
-#if !TARGET_BROWSER
+#if !TARGET_BROWSER && !TARGET_WASI
[UnconditionalSuppressMessage("SingleFile", "IL3000: Avoid accessing Assembly file path when publishing as a single file",
Justification = "Single File apps should always set APP_CONTEXT_BASE_DIRECTORY therefore code handles Assembly.Location equals null")]
private static string GetBaseDirectoryCore()
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
index 4d6c58e3784e6f..f839d0e9bf65a5 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
@@ -1322,12 +1322,12 @@ protected unsafe void WriteEventWithRelatedActivityIdCore(int eventId, Guid* rel
if (m_Dispatchers != null && metadata.EnabledForAnyListener)
{
-#if MONO && !TARGET_BROWSER
+#if MONO && !TARGET_BROWSER && !TARGET_WASI
// On Mono, managed events from NativeRuntimeEventSource are written using WriteEventCore which can be
// written doubly because EventPipe tries to pump it back up to EventListener via NativeRuntimeEventSource.ProcessEvents.
// So we need to prevent this from getting written directly to the Listeners.
if (this.GetType() != typeof(NativeRuntimeEventSource))
-#endif // MONO && !TARGET_BROWSER
+#endif // MONO && !TARGET_BROWSER && !TARGET_WASI
{
var eventCallbackArgs = new EventWrittenEventArgs(this, eventId, pActivityId, relatedActivityId);
WriteToAllListeners(eventCallbackArgs, eventDataCount, data);
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs
index fe14a0aa99a19f..283404991036ab 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileStatus.Unix.cs
@@ -57,7 +57,7 @@ private bool HasReadOnlyFlag
return false;
}
-#if TARGET_BROWSER
+#if TARGET_BROWSER || TARGET_WASI
var mode = ((UnixFileMode)_fileCache.Mode & FileSystem.ValidUnixFileModes);
bool isUserReadOnly = (mode & UnixFileMode.UserRead) != 0 && // has read permission
(mode & UnixFileMode.UserWrite) == 0; // but not write permission
@@ -81,7 +81,7 @@ private bool HasReadOnlyFlag
}
}
-#if !TARGET_BROWSER
+#if !TARGET_BROWSER && !TARGET_WASI
// HasReadOnlyFlag cache.
// Must only be used after calling EnsureCachesInitialized.
private int _isReadOnlyCache;
@@ -394,7 +394,7 @@ private unsafe void SetAccessOrWriteTimeCore(SafeFileHandle? handle, string? pat
long seconds = time.ToUnixTimeSeconds();
long nanoseconds = UnixTimeSecondsToNanoseconds(time, seconds);
-#if TARGET_BROWSER
+#if TARGET_BROWSER || TARGET_WASI
buf[0].TvSec = seconds;
buf[0].TvNsec = nanoseconds;
buf[1].TvSec = seconds;
@@ -499,7 +499,7 @@ internal void RefreshCaches(SafeFileHandle? handle, ReadOnlySpan path)
{
Debug.Assert(handle is not null || path.Length > 0);
-#if !TARGET_BROWSER
+#if !TARGET_BROWSER && !TARGET_WASI
_isReadOnlyCache = -1;
#endif
int rv = handle is not null ?
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs
index f6445df9671b8f..00095ffb7f48bd 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs
@@ -265,10 +265,10 @@ public static Assembly LoadFile(string path)
return result;
// we cannot check for file presence on BROWSER. The files could be embedded and not physically present.
-#if !TARGET_BROWSER
+#if !TARGET_BROWSER && !TARGET_WASI
if (!File.Exists(normalizedPath))
throw new FileNotFoundException(SR.Format(SR.FileNotFound_LoadFile, normalizedPath), normalizedPath);
-#endif // !TARGET_BROWSER
+#endif // !TARGET_BROWSER && !TARGET_WASI
AssemblyLoadContext alc = new IndividualAssemblyLoadContext($"Assembly.LoadFile({normalizedPath})");
result = alc.LoadFromAssemblyPath(normalizedPath);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.Browser.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.Browser.cs
index 3fcfb1465a9dd3..04e9d251c31f5b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.Browser.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/RuntimeInformation.Browser.cs
@@ -5,7 +5,13 @@ namespace System.Runtime.InteropServices
{
public static partial class RuntimeInformation
{
+#if TARGET_BROWSER
public static string OSDescription => "Browser";
+#elif TARGET_WASI
+ public static string OSDescription => "WASI";
+#else
+ #error
+#endif
public static Architecture OSArchitecture => Architecture.Wasm;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs
index 95750074698b0a..bc41f1bde322e5 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Windows.cs
@@ -18,7 +18,7 @@ private EventWaitHandle(SafeWaitHandle handle)
private void CreateEventCore(bool initialState, EventResetMode mode, string? name, out bool createdNew)
{
-#if TARGET_UNIX || TARGET_BROWSER
+#if TARGET_UNIX || TARGET_BROWSER || TARGET_WASI
if (name != null)
throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
#endif
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs
index ab5663297cdc52..10a91926c3e02b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Windows.cs
@@ -24,7 +24,7 @@ private void CreateMutexCore(bool initiallyOwned, string? name, out bool created
if (mutexHandle.IsInvalid)
{
mutexHandle.SetHandleAsInvalid();
-#if TARGET_UNIX || TARGET_BROWSER
+#if TARGET_UNIX || TARGET_BROWSER || TARGET_WASI
if (errorCode == Interop.Errors.ERROR_FILENAME_EXCED_RANGE)
// On Unix, length validation is done by CoreCLR's PAL after converting to utf-8
throw new ArgumentException(SR.Argument_WaitHandleNameTooLong, nameof(name));
@@ -56,7 +56,7 @@ private static OpenExistingResult OpenExistingWorker(string name, out Mutex? res
myHandle.Dispose();
-#if TARGET_UNIX || TARGET_BROWSER
+#if TARGET_UNIX || TARGET_BROWSER || TARGET_WASI
if (errorCode == Interop.Errors.ERROR_FILENAME_EXCED_RANGE)
{
// On Unix, length validation is done by CoreCLR's PAL after converting to utf-8
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Overlapped.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Overlapped.cs
index 0f130cdc53aa82..29446e444073c4 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/Overlapped.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Overlapped.cs
@@ -184,7 +184,7 @@ public static void Free(NativeOverlapped* nativeOverlappedPtr)
_pNativeOverlapped = pNativeOverlapped;
#if FEATURE_PERFTRACING
-#if !(TARGET_BROWSER && !FEATURE_WASM_THREADS)
+#if !((TARGET_BROWSER || TARGET_WASI) && !FEATURE_WASM_THREADS)
if (NativeRuntimeEventSource.Log.IsEnabled())
NativeRuntimeEventSource.Log.ThreadPoolIOPack(pNativeOverlapped);
#endif
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs
index a4cb8323ef5b21..027e9fe93f4683 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Windows.cs
@@ -23,7 +23,7 @@ private void CreateSemaphoreCore(int initialCount, int maximumCount, string? nam
Debug.Assert(maximumCount >= 1);
Debug.Assert(initialCount <= maximumCount);
-#if TARGET_UNIX || TARGET_BROWSER
+#if TARGET_UNIX || TARGET_BROWSER || TARGET_WASI
if (name != null)
throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
#endif
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs
index 0f39e88c8c6ef4..e5c852dd706a0e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs
@@ -147,7 +147,7 @@ public Thread(ParameterizedThreadStart start, int maxStackSize)
Initialize();
}
-#if !TARGET_BROWSER || FEATURE_WASM_THREADS
+#if (!TARGET_BROWSER && !TARGET_WASI) || FEATURE_WASM_THREADS
[UnsupportedOSPlatformGuard("browser")]
internal static bool IsThreadStartSupported => true;
internal static bool IsInternalThreadStartSupported => true;
diff --git a/src/mono/CMakeLists.txt b/src/mono/CMakeLists.txt
index f7bd010d5d9c18..9e9ae57e192caf 100644
--- a/src/mono/CMakeLists.txt
+++ b/src/mono/CMakeLists.txt
@@ -238,23 +238,17 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
set(INTERNAL_ZLIB 1)
elseif(CMAKE_SYSTEM_NAME STREQUAL "WASI")
set(HOST_WASI 1)
- add_definitions(-D_WASI_EMULATED_SIGNAL -D_WASI_EMULATED_MMAN -DHOST_WASI)
+ add_definitions(-D_WASI_EMULATED_PROCESS_CLOCKS -D_WASI_EMULATED_SIGNAL -D_WASI_EMULATED_MMAN -DHOST_WASI)
add_definitions(-DNO_GLOBALIZATION_SHIM)
add_definitions(-D_THREAD_SAFE)
- add_definitions(-DGEN_PINVOKE)
+ add_definitions(-DDISABLE_SOCKET_TRANSPORT)
+ add_definitions(-DDISABLE_EGD_SOCKET)
+ add_definitions(-DDISABLE_EVENTPIPE)
+ set(ENABLE_PERFTRACING 0)
set(DISABLE_SHARED_LIBS 1)
set(INTERNAL_ZLIB 1)
set(DISABLE_EXECUTABLES 1)
set(STATIC_COMPONENTS 1)
-
- set(WASI_DRIVER_SOURCES
- wasi/mono-wasi-driver/driver.c
- wasi/mono-wasi-driver/stubs.c
- wasi/mono-wasi-driver/synthetic-pthread.c
- )
- add_library(mono-wasi-driver STATIC ${WASI_DRIVER_SOURCES})
- target_compile_options(mono-wasi-driver PRIVATE -Wno-missing-prototypes -Wno-strict-prototypes)
- install(TARGETS mono-wasi-driver LIBRARY)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(HOST_WIN32 1)
set(EXE_SUFFIX ".exe")
@@ -326,6 +320,9 @@ elseif(TARGET_SYSTEM_NAME STREQUAL "Emscripten")
endif()
elseif(TARGET_SYSTEM_NAME STREQUAL "WASI")
set(TARGET_WASI 1)
+ if (CMAKE_BUILD_TYPE STREQUAL "Release")
+ add_compile_options(-Os)
+ endif()
elseif(TARGET_SYSTEM_NAME STREQUAL "Windows")
set(TARGET_WIN32 1)
elseif(TARGET_SYSTEM_NAME STREQUAL "SunOS")
@@ -656,7 +653,11 @@ elseif(HOST_OSX AND NOT HOST_MACCAT)
set(OSX_ICU_LIBRARY_PATH /usr/lib/libicucore.dylib)
set(ICU_FLAGS "-DTARGET_UNIX -DU_DISABLE_RENAMING -Wno-reserved-id-macro -Wno-documentation -Wno-documentation-unknown-command -Wno-switch-enum -Wno-covered-switch-default -Wno-extra-semi-stmt -Wno-unknown-warning-option -Wno-deprecated-declarations")
set(HAVE_SYS_ICU 1)
-elseif(HOST_WASM)
+elseif(HOST_WASI)
+ set(HAVE_SYS_ICU 0)
+ set(STATIC_ICU 1)
+ set(ICU_LIBS "icucore")
+elseif(HOST_BROWSER)
set(ICU_FLAGS "-DPALEXPORT=\"\" -DU_DISABLE_RENAMING -DHAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS -DHAVE_SET_MAX_VARIABLE -DTARGET_UNIX -Wno-reserved-id-macro -Wno-documentation -Wno-documentation-unknown-command -Wno-switch-enum -Wno-covered-switch-default -Wno-extra-semi-stmt -Wno-unknown-warning-option")
set(HAVE_SYS_ICU 1)
set(STATIC_ICU 1)
@@ -713,6 +714,8 @@ elseif(GC_SUSPEND STREQUAL "default")
# use preemptive
elseif(TARGET_SYSTEM_NAME STREQUAL "Emscripten")
# use preemptive
+ elseif(TARGET_SYSTEM_NAME STREQUAL "WASI")
+ # use preemptive
else()
set(ENABLE_HYBRID_SUSPEND 1)
endif()
@@ -880,7 +883,7 @@ endif()
add_subdirectory("${CLR_SRC_NATIVE_DIR}/public" public_apis)
add_subdirectory(mono)
-if (ENABLE_MSCORDBI AND NOT TARGET_ARCH STREQUAL "arm64" AND NOT CMAKE_CROSSCOMPILING AND NOT TARGET_IOS AND NOT TARGET_ANDROID AND NOT TARGET_BROWSER AND NOT HOST_MACCAT)
+if (ENABLE_MSCORDBI AND NOT TARGET_ARCH STREQUAL "arm64" AND NOT CMAKE_CROSSCOMPILING AND NOT TARGET_IOS AND NOT TARGET_ANDROID AND NOT TARGET_BROWSER AND NOT TARGET_WASI AND NOT HOST_MACCAT)
add_subdirectory(dlls/mscordbi)
add_subdirectory(dlls/dbgshim)
endif()
diff --git a/src/mono/Directory.Build.props b/src/mono/Directory.Build.props
index 6bc85c60667b94..3c61363c9791cd 100644
--- a/src/mono/Directory.Build.props
+++ b/src/mono/Directory.Build.props
@@ -40,10 +40,18 @@
$([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)', 'wasm', 'emsdk'))
- true
+ true
$(ProvisionEmscriptenDir.Replace('\', '/'))
+
+
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsObjDir)', 'wasi-sdk'))
+ $(ProvisionWasiSdkDir.Replace('\', '/'))
+ true
+ true
+
+
$(TargetOS).$(Platform).$(Configuration)
$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'mono', '$(TargetOS).$(Platform).$(Configuration)'))
diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
index f48e722486cc20..411da5e3901a54 100644
--- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -121,13 +121,13 @@
$(DefineConstants);MONO_FEATURE_SRE
true
- true
- true
+ true
+ true
true
true
- true
- true
- true
+ true
+ true
+ true
true
@@ -275,16 +275,16 @@
-
+
-
+
-
+
-
+
@@ -302,6 +302,9 @@
+
+
+
diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs
index 37a5f9aa149f48..48c545aaaaacf5 100644
--- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs
@@ -65,7 +65,7 @@ public partial class Thread
private StartHelper? _startHelper;
internal ExecutionContext? _executionContext;
internal SynchronizationContext? _synchronizationContext;
-#if TARGET_UNIX || TARGET_BROWSER
+#if TARGET_UNIX || TARGET_BROWSER || TARGET_WASI
internal WaitSubsystem.ThreadWaitInfo? _waitInfo;
#endif
@@ -138,7 +138,7 @@ internal static int OptimalMaxSpinWaitsPerSpinIteration
return 7;
}
}
-#if TARGET_UNIX || TARGET_BROWSER
+#if TARGET_UNIX || TARGET_BROWSER || TARGET_WASI
internal WaitSubsystem.ThreadWaitInfo WaitInfo
{
get
@@ -196,7 +196,7 @@ public static int GetCurrentProcessorId()
public void Interrupt()
{
-#if TARGET_UNIX || TARGET_BROWSER // TODO: https://github.com/dotnet/runtime/issues/49521
+#if TARGET_UNIX || TARGET_BROWSER || TARGET_WASI // TODO: https://github.com/dotnet/runtime/issues/49521
WaitSubsystem.Interrupt(this);
#endif
InterruptInternal(this);
@@ -208,7 +208,7 @@ public bool Join(int millisecondsTimeout)
return JoinInternal(this, millisecondsTimeout);
}
-#if TARGET_UNIX || TARGET_BROWSER
+#if TARGET_UNIX || TARGET_BROWSER || TARGET_WASI
[DynamicDependency(nameof(OnThreadExiting))]
#endif
private void Initialize()
@@ -300,7 +300,7 @@ internal void ClearWaitSleepJoinState()
private static void OnThreadExiting(Thread thread)
{
-#if TARGET_UNIX || TARGET_BROWSER
+#if TARGET_UNIX || TARGET_BROWSER || TARGET_WASI
thread.WaitInfo.OnThreadExiting();
#endif
}
diff --git a/src/mono/cmake/config.h.in b/src/mono/cmake/config.h.in
index f53d12433aae82..13704912bea374 100644
--- a/src/mono/cmake/config.h.in
+++ b/src/mono/cmake/config.h.in
@@ -171,6 +171,9 @@
/* Define to 1 if you have the header file. */
#cmakedefine HAVE_PWD_H 1
+/* Define to 1 if you have the header file. */
+#cmakedefine HAVE_GRP_H 1
+
/* Define to 1 if you have the header file. */
#cmakedefine HAVE_SYS_SELECT_H 1
diff --git a/src/mono/cmake/configure.cmake b/src/mono/cmake/configure.cmake
index ae55fd112b321e..db78672ce68920 100644
--- a/src/mono/cmake/configure.cmake
+++ b/src/mono/cmake/configure.cmake
@@ -23,7 +23,7 @@ if(HOST_SOLARIS)
endif()
if(HOST_WASI)
- set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WASI_EMULATED_SIGNAL -D_WASI_EMULATED_MMAN")
+ set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WASI_EMULATED_PROCESS_CLOCKS -D_WASI_EMULATED_SIGNAL -D_WASI_EMULATED_MMAN")
endif()
function(ac_check_headers)
@@ -85,13 +85,18 @@ ac_check_funcs (
gethrtime read_real_time gethostbyname gethostbyname2 getnameinfo getifaddrs
access inet_ntop Qp2getifaddrs getpid mktemp)
-if (HOST_LINUX OR HOST_BROWSER)
+if (HOST_LINUX OR HOST_BROWSER OR HOST_WASI)
# sysctl is deprecated on Linux and doesn't work on Browser
set(HAVE_SYS_SYSCTL_H 0)
else ()
check_include_files("sys/types.h;sys/sysctl.h" HAVE_SYS_SYSCTL_H)
endif()
+if (HOST_WASI)
+ # sysctl is deprecated on Linux and doesn't work on WASI
+ set(HAVE_GETRUSAGE 0)
+endif()
+
check_include_files("sys/types.h;sys/user.h" HAVE_SYS_USER_H)
if(NOT HOST_DARWIN)
@@ -99,7 +104,9 @@ if(NOT HOST_DARWIN)
ac_check_funcs (getentropy)
endif()
-find_package(Threads)
+if(NOT DISABLE_THREADS)
+ find_package(Threads)
+endif()
# Needed to find pthread_ symbols
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}")
diff --git a/src/mono/mono.proj b/src/mono/mono.proj
index 9b18ac091e2702..7bc2f4dcb7d617 100644
--- a/src/mono/mono.proj
+++ b/src/mono/mono.proj
@@ -27,7 +27,7 @@
$(CoreClrLibName)
$(LibPrefix)$(MonoSharedLibName)$(LibSuffix)
$(LibPrefix)$(MonoLibName)$(StaticLibSuffix)
- $(MonoStaticLibFileName)
+ $(MonoStaticLibFileName)
$(MonoSharedLibFileName)
mono-aot-cross$(ExeSuffix)
mono-aot-cross.pdb
@@ -61,7 +61,7 @@
coop
- preemptive
+ preemptive
hybrid
@@ -69,6 +69,7 @@
true
+ true
true
true
false
@@ -79,12 +80,12 @@
true
-
+
-
+
<_MonoCMakeArgs Include="-DENABLE_WERROR=1"/>
@@ -97,6 +98,7 @@
+
@@ -138,15 +140,15 @@
- .sh
+
.ps1
$(ProvisionEmscriptenDir)
$([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)', 'wasm'))
emsdk
%(_VersionLines.Identity)
- ./emsdk$(EmsdkExt) install $(EmscriptenVersion)
- ./emsdk$(EmsdkExt) activate $(EmscriptenVersion)
+ $(EMSDK_PATH)/emsdk$(EmsdkExt) install $(EmscriptenVersion)
+ $(EMSDK_PATH)/emsdk$(EmsdkExt) activate $(EmscriptenVersion)
powershell -NonInteractive -command "& $(InstallCmd); Exit $LastExitCode "
powershell -NonInteractive -command "& $(ActivateCmd); Exit $LastExitCode "
@@ -160,6 +162,49 @@
IgnoreStandardErrorWarningFormat="true" />
+
+
+
+
+
+
+
+ $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)', 'wasi'))
+ %(_VersionLines.Identity)
+ https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WasiSdkVersion)/wasi-sdk-$(WasiSdkVersion).0-linux.tar.gz
+ https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WasiSdkVersion)/wasi-sdk-$(WasiSdkVersion).0-macos.tar.gz
+ https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WasiSdkVersion)/wasi-sdk-$(WasiSdkVersion).0-mingw.tar.gz
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %(_ActualVersionLines.Identity)
+ %(_ExpectedVersionLines.Identity)
+
+
+
+
@@ -209,7 +254,7 @@
<_MonoCMakeArgs Condition="'$(_MonoUseNinja)' == 'true'" Include="-G Ninja"/>
- <_MonoCMakeArgs Include="-DCMAKE_INSTALL_PREFIX="$(MonoObjDir)out""/>
+ <_MonoCMakeArgs Include="-DCMAKE_INSTALL_PREFIX="$(MonoObjDir.Replace('\','/'))out""/>
<_MonoCMakeArgs Include="-DCMAKE_INSTALL_LIBDIR=lib"/>
<_MonoCMakeArgs Include="-DCMAKE_BUILD_TYPE=$(Configuration)"/>
<_MonoCMakeArgs Condition="'$(CMakeArgs)' != ''" Include="$(CMakeArgs)"/>
@@ -341,30 +386,50 @@
<_MonoBuildEnv Condition="'$(BuildArchitecture)' == 'arm64'" Include="arch -arch arm64" />
-
+
<_MonoMinimal Condition="'$(Configuration)' == 'Release'">,debugger_agent,log_dest
<_MonoMinimal Condition="'$(Configuration)' == 'Release' and '$(MonoEnableAssertMessages)' != 'true'">$(_MonoMinimal),assert_messages
<_MonoMinimal Condition="'$(MonoWasmThreads)' != 'true'">$(_MonoMinimal),threads
<_MonoMinimal Condition="'$(MonoWasmThreadsNoUser)' == 'true'">$(_MonoMinimal),wasm_user_threads
-
+
<_MonoCMakeArgs Include="-DENABLE_MINIMAL=jit,sgen_major_marksweep_conc,sgen_split_nursery,sgen_gc_bridge,sgen_toggleref,sgen_debug_helpers,sgen_binary_protocol,logging,interpreter,qcalls$(_MonoMinimal)"/>
<_MonoCMakeArgs Include="-DENABLE_INTERP_LIB=1"/>
<_MonoCMakeArgs Include="-DDISABLE_ICALL_TABLES=1"/>
<_MonoCMakeArgs Include="-DENABLE_ICALL_EXPORT=1"/>
<_MonoCMakeArgs Include="-DENABLE_LAZY_GC_THREAD_CREATION=1"/>
- <_MonoCMakeArgs Include="-DENABLE_LLVM_RUNTIME=1"/>
- <_MonoCMakeArgs Include="-DEMSCRIPTEN_SYSTEM_PROCESSOR=wasm"/>
<_MonoCFLAGS Include="-fexceptions"/>
<_MonoCFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-pthread"/>
<_MonoCFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-D_GNU_SOURCE=1" />
<_MonoCXXFLAGS Include="-fexceptions"/>
<_MonoCXXFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-pthread"/>
<_MonoCXXFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-D_GNU_SOURCE=1" />
+
+
+
+ <_MonoCMakeArgs Include="-DENABLE_LLVM_RUNTIME=1"/>
+ <_MonoCMakeArgs Include="-DEMSCRIPTEN_SYSTEM_PROCESSOR=wasm"/>
<_MonoCFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm-threads', 'native', 'include'))$(EscapedQuoteW)"/>
<_MonoCFLAGS Condition="'$(MonoWasmThreads)' != 'true'" Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm', 'native', 'include'))$(EscapedQuoteW)"/>
+
+
+
+ <_MonoCFLAGS Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(MonoProjectRoot)', 'wasi', 'include').Replace('\','/'))$(EscapedQuoteW)"/>
+ <_MonoCFLAGS Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(MonoProjectRoot)', 'wasi', 'mono-include').Replace('\','/'))$(EscapedQuoteW)"/>
+ <_MonoCFLAGS Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(RepoRoot)', 'src', 'native', 'public').Replace('\','/'))$(EscapedQuoteW)"/>
+ <_MonoCFLAGS Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(MonoProjectRoot)', 'mono', 'eglib').Replace('\','/'))$(EscapedQuoteW)"/>
+ <_MonoCFLAGS Include="-D_WASI_EMULATED_PROCESS_CLOCKS"/>
+ <_MonoCFLAGS Include="-D_WASI_EMULATED_SIGNAL"/>
+ <_MonoCFLAGS Include="-D_WASI_EMULATED_MMAN"/>
+
+ <_MonoCFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm-threads', 'native', 'include').Replace('\','/'))$(EscapedQuoteW)"/>
+ <_MonoCFLAGS Condition="'$(MonoWasmThreads)' != 'true'" Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm', 'native', 'include').Replace('\','/'))$(EscapedQuoteW)"/>
+
<_MonoCCOption>CC="$(XcodeDir)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang"
@@ -490,7 +555,7 @@
<_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT=1"/>
-
+
<_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_PERFTRACING_LISTEN_PORTS=1"/>
<_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT=1"/>
<_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_CONNECT_PORTS=1" />
@@ -514,19 +579,22 @@
- $([MSBuild]::EnsureTrailingSlash('$(EMSDK_PATH)'))
+ $([MSBuild]::EnsureTrailingSlash('$(EMSDK_PATH)').Replace('\', '/'))
+ $([MSBuild]::EnsureTrailingSlash('$(WASI_SDK_PATH)').Replace('\', '/'))
<_MonoCMakeConfigureCommand>cmake @(_MonoCMakeArgs, ' ') $(MonoCMakeExtraArgs) "$(MonoProjectRoot.TrimEnd('\/'))"
- <_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' != 'true' and '$(_MonoSkipInitCompiler)' != 'true' and '$(HostOS)' != 'windows'">sh -c 'build_arch="$(_CompilerTargetArch)" compiler="$(MonoCCompiler)" . "$(RepositoryEngineeringCommonDir)native/init-compiler.sh" && @(_MonoBuildEnv, ' ') $(_MonoCMakeConfigureCommand)'
- <_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' != 'true' and '$(_MonoSkipInitCompiler)' == 'true' and '$(HostOS)' != 'windows'">$(_MonoCCOption) $(_MonoCXXOption) @(_MonoBuildEnv, ' ') $(_MonoCMakeConfigureCommand)
- <_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' != 'true' and '$(HostOS)' == 'windows'">call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" $(_CompilerTargetArch) && cd /D "$(MonoObjDir)" && @(_MonoBuildEnv, ' ') $(_MonoCMakeConfigureCommand)
+ <_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' != 'true' and '$(TargetsWasi)' != 'true' and '$(_MonoSkipInitCompiler)' != 'true' and '$(HostOS)' != 'windows'">sh -c 'build_arch="$(_CompilerTargetArch)" compiler="$(MonoCCompiler)" . "$(RepositoryEngineeringCommonDir)native/init-compiler.sh" && @(_MonoBuildEnv, ' ') $(_MonoCMakeConfigureCommand)'
+ <_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' != 'true' and '$(TargetsWasi)' != 'true' and '$(_MonoSkipInitCompiler)' == 'true' and '$(HostOS)' != 'windows'">$(_MonoCCOption) $(_MonoCXXOption) @(_MonoBuildEnv, ' ') $(_MonoCMakeConfigureCommand)
+ <_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' != 'true' and '$(TargetsWasi)' != 'true' and '$(HostOS)' == 'windows'">call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" $(_CompilerTargetArch) && cd /D "$(MonoObjDir)" && @(_MonoBuildEnv, ' ') $(_MonoCMakeConfigureCommand)
<_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' == 'true' and '$(HostOS)' != 'windows'">bash -c 'source $(EMSDK_PATH)/emsdk_env.sh 2>&1 && emcmake $(_MonoCMakeConfigureCommand)'
<_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' == 'true' and '$(HostOS)' == 'windows'">call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" && call "$([MSBuild]::NormalizePath('$(EMSDK_PATH)', 'emsdk_env.bat'))" && emcmake $(_MonoCMakeConfigureCommand)
+ <_MonoCMakeConfigureCommand Condition="'$(TargetsWasi)' == 'true'">$(_MonoCMakeConfigureCommand) -DWASI_SDK_PREFIX=$(WASI_SDK_PATH) -DCMAKE_SYSROOT=$(WASI_SDK_PATH)share/wasi-sysroot -DCMAKE_TOOLCHAIN_FILE=$(WASI_SDK_PATH)share/cmake/wasi-sdk.cmake -DCMAKE_CXX_FLAGS="--sysroot=$(WASI_SDK_PATH)share/wasi-sysroot"
+
<_MonoCMakeBuildCommand>cmake --build . --target install --config $(Configuration)
<_MonoCMakeBuildCommand Condition="'$(MonoVerboseBuild)' == 'true'">$(_MonoCMakeBuildCommand) --verbose
<_MonoCMakeBuildCommand Condition="'$(_MonoUseNinja)' != 'true'">$(_MonoCMakeBuildCommand) --parallel $([System.Environment]::ProcessorCount)
- <_MonoCMakeBuildCommand Condition="'$(TargetsBrowser)' != 'true' and '$(HostOS)' != 'windows'">@(_MonoBuildEnv, ' ') $(_MonoCMakeBuildCommand)
- <_MonoCMakeBuildCommand Condition="'$(TargetsBrowser)' != 'true' and '$(HostOS)' == 'windows'">call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" $(_CompilerTargetArch) && cd /D "$(MonoObjDir)" && @(_MonoBuildEnv, ' ') $(_MonoCMakeBuildCommand)
+ <_MonoCMakeBuildCommand Condition="'$(TargetsBrowser)' != 'true' and '$(TargetsWasi)' != 'true' and '$(HostOS)' != 'windows'">@(_MonoBuildEnv, ' ') $(_MonoCMakeBuildCommand)
+ <_MonoCMakeBuildCommand Condition="'$(TargetsBrowser)' != 'true' and '$(TargetsWasi)' != 'true' and '$(HostOS)' == 'windows'">call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" $(_CompilerTargetArch) && cd /D "$(MonoObjDir)" && @(_MonoBuildEnv, ' ') $(_MonoCMakeBuildCommand)
<_MonoCMakeBuildCommand Condition="'$(TargetsBrowser)' == 'true' and '$(HostOS)' == 'windows'">call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" && $(_MonoCMakeBuildCommand)
@@ -822,6 +890,7 @@
CheckEnv;GetXcodeDir;GenerateRuntimeVersionFile;BuildMonoRuntime;BuildMonoCross
GenerateRuntimeVersionFile;ProvisionEmscripten;$(MonoDependsOnTargets)
+ GenerateRuntimeVersionFile;ProvisionWasiSdk;ValidateWasiSdk;$(MonoDependsOnTargets)
@@ -830,7 +899,7 @@
<_MonoRuntimeFilePath Condition="'$(TargetsWindows)' == 'true'">$(MonoObjDir)out\bin\$(MonoFileName)
<_MonoRuntimeFilePath Condition="'$(_MonoRuntimeFilePath)' == ''">$(MonoObjDir)out\lib\$(MonoFileName)
<_MonoRuntimeStaticFilePath Condition="'$(TargetsMacCatalyst)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true' or '$(TargetsAndroid)' == 'true' or '$(TargetsLinuxBionic)' == 'true'">$(MonoObjDir)out\lib\$(MonoStaticLibFileName)
- <_MonoIncludeInterpStaticFiles Condition="'$(TargetsBrowser)' == 'true'">true
+ <_MonoIncludeInterpStaticFiles Condition="'$(TargetsBrowser)' == 'true' or '$(TargetsWasi)' == 'true'">true
<_MonoIncludeIcuFiles Condition="'$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true' or '$(TargetsMacCatalyst)' == 'true'">true
diff --git a/src/mono/mono/component/debugger-agent.c b/src/mono/mono/component/debugger-agent.c
index 6134e86e0d30b2..6956c42ab28b25 100644
--- a/src/mono/mono/component/debugger-agent.c
+++ b/src/mono/mono/component/debugger-agent.c
@@ -5575,12 +5575,11 @@ decode_value_compute_size (MonoType *t, int type, MonoDomain *domain, guint8 *bu
decode_int (buf, &buf, limit); //not used
}
} else if (type == MONO_TYPE_VALUETYPE) {
- MonoClass *klass;
MonoDomain *d;
decode_byte (buf, &buf, limit);
if (CHECK_PROTOCOL_VERSION(2, 61))
decode_byte (buf, &buf, limit); //ignore is boxed
- klass = decode_typeid (buf, &buf, limit, &d, &err);
+ decode_typeid (buf, &buf, limit, &d, &err);
ret += decode_vtype_compute_size (NULL, domain, buf, &buf, limit, from_by_ref_value_type);
} else {
goto end;
diff --git a/src/mono/mono/mini/CMakeLists.txt b/src/mono/mono/mini/CMakeLists.txt
index 30df4bac1f7797..0848baf8593e44 100644
--- a/src/mono/mono/mini/CMakeLists.txt
+++ b/src/mono/mono/mini/CMakeLists.txt
@@ -340,7 +340,7 @@ endif()
if(HOST_WIN32)
set(mini_sources "${mini_sources};${VERSION_FILE_RC_PATH}") # this is generated by GenerateNativeVersionFile in Arcade
-elseif(NOT HOST_BROWSER)
+elseif(NOT HOST_BROWSER AND NOT HOST_WASI)
set(mini_sources "${mini_sources};${VERSION_FILE_PATH}") # this is generated by GenerateNativeVersionFile in Arcade
endif()
diff --git a/src/mono/mono/utils/mono-rand.c b/src/mono/mono/utils/mono-rand.c
index cb78275d75677d..0f64d3b9eacdbd 100644
--- a/src/mono/mono/utils/mono-rand.c
+++ b/src/mono/mono/utils/mono-rand.c
@@ -121,6 +121,7 @@ mono_getentropy (guchar *buffer, gssize buffer_size, MonoError *error)
}
#endif /* HAVE_GETENTROPY */
+#if !defined(DISABLE_EGD_SOCKET)
static void
get_entropy_from_egd (const char *path, guchar *buffer, gssize buffer_size, MonoError *error)
{
@@ -222,6 +223,7 @@ mono_rand_open (void)
return TRUE;
}
+#endif /* !DISABLE_EGD_SOCKET */
gpointer
mono_rand_init (const guchar *seed, gssize seed_size)
@@ -250,9 +252,9 @@ mono_rand_try_get_bytes (gpointer *handle, guchar *buffer, gssize buffer_size, M
if (res == 1)
return TRUE;
+#elif !defined(DISABLE_EGD_SOCKET)
/* getrandom() or getentropy() function is not available: failed with
ENOSYS or EPERM. Fall back on reading from /dev/urandom. */
-#endif
if (use_egd) {
char *socket_path = g_getenv ("MONO_EGD_SOCKET");
@@ -263,21 +265,22 @@ mono_rand_try_get_bytes (gpointer *handle, guchar *buffer, gssize buffer_size, M
}
get_entropy_from_egd (socket_path, buffer, buffer_size, error);
g_free (socket_path);
- } else {
- /* Read until the buffer is filled. This may block if using NAME_DEV_RANDOM. */
- while (buffer_size > 0) {
- gssize const err = read (file, buffer, buffer_size);
- if (err < 0) {
- if (errno == EINTR)
- continue;
- g_warning("Entropy error! Error in read (%s).", strerror (errno));
- /* exception will be thrown in managed code */
- mono_error_set_execution_engine (error, "Entropy error! Error in read (%s).", strerror (errno));
- return FALSE;
- }
- buffer += err;
- buffer_size -= err;
+ return TRUE;
+ }
+#endif
+ /* Read until the buffer is filled. This may block if using NAME_DEV_RANDOM. */
+ while (buffer_size > 0) {
+ gssize const err = read (file, buffer, buffer_size);
+ if (err < 0) {
+ if (errno == EINTR)
+ continue;
+ g_warning("Entropy error! Error in read (%s).", strerror (errno));
+ /* exception will be thrown in managed code */
+ mono_error_set_execution_engine (error, "Entropy error! Error in read (%s).", strerror (errno));
+ return FALSE;
}
+ buffer += err;
+ buffer_size -= err;
}
return TRUE;
}
diff --git a/src/mono/sample/wasi/CommonAssemblyInfo.cs b/src/mono/sample/wasi/CommonAssemblyInfo.cs
new file mode 100644
index 00000000000000..1e407edc804221
--- /dev/null
+++ b/src/mono/sample/wasi/CommonAssemblyInfo.cs
@@ -0,0 +1,4 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+[assembly:System.Runtime.Versioning.SupportedOSPlatform("wasi")]
diff --git a/src/mono/sample/wasi/Directory.Build.props b/src/mono/sample/wasi/Directory.Build.props
new file mode 100644
index 00000000000000..f2ecb0d30b5db4
--- /dev/null
+++ b/src/mono/sample/wasi/Directory.Build.props
@@ -0,0 +1,37 @@
+
+
+
+ Exe
+ wasi
+
+
+
+
+
+
+ bin
+
+
+ false
+
+
+
+
+ false
+ true
+ false
+ false
+ false
+ true
+
+
+
+
+
+
+
+
+
diff --git a/src/mono/sample/wasi/Directory.Build.targets b/src/mono/sample/wasi/Directory.Build.targets
new file mode 100644
index 00000000000000..1e6a5fff8268f8
--- /dev/null
+++ b/src/mono/sample/wasi/Directory.Build.targets
@@ -0,0 +1,72 @@
+
+
+
+
+
+ true
+
+
+
+
+
+ <_ScriptExt Condition="'$(OS)' == 'Windows_NT'">.cmd
+ <_ScriptExt Condition="'$(OS)' != 'Windows_NT'">.sh
+ <_Dotnet>$(RepoRoot)dotnet$(_ScriptExt)
+ <_AOTFlag Condition="'$(RunAOTCompilation)' != ''">/p:RunAOTCompilation=$(RunAOTCompilation)
+ <_WasmMainJSFileName>$([System.IO.Path]::GetFileName('$(WasmMainJSPath)'))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %(_VersionLines.Identity)
+ https://github.com/bytecodealliance/wasmtime/releases/download/v$(WasmtimeVersion)/wasmtime-v$(WasmtimeVersion)-x86_64-linux.tar.xz
+ https://github.com/bytecodealliance/wasmtime/releases/download/v$(WasmtimeVersion)/wasmtime-v$(WasmtimeVersion)-x86_64-macos.tar.xz
+ https://github.com/bytecodealliance/wasmtime/releases/download/v$(WasmtimeVersion)/wasmtime-v$(WasmtimeVersion)-x86_64-windows.zip
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mono/sample/wasi/console/Program.cs b/src/mono/sample/wasi/console/Program.cs
new file mode 100644
index 00000000000000..c65033a418ebb4
--- /dev/null
+++ b/src/mono/sample/wasi/console/Program.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Threading.Tasks;
+
+public class Test
+{
+ public static int Main()
+ {
+ Console.WriteLine("");
+ Console.WriteLine("Hello World!");
+ Console.WriteLine("");
+ return 0;
+ }
+}
diff --git a/src/mono/sample/wasi/console/Wasi.Console.Sample.csproj b/src/mono/sample/wasi/console/Wasi.Console.Sample.csproj
new file mode 100644
index 00000000000000..da5ab16c38d0f9
--- /dev/null
+++ b/src/mono/sample/wasi/console/Wasi.Console.Sample.csproj
@@ -0,0 +1,13 @@
+
+
+ $(NetCoreAppCurrent)
+ false
+
+
+
+ <_SampleProject>Wasi.Console.Sample.csproj
+ <_SampleAssembly>Wasi.Console.Sample.dll
+
+
+
+
diff --git a/src/mono/wasi/Makefile b/src/mono/wasi/Makefile
deleted file mode 100644
index 53ae87f4f76eaf..00000000000000
--- a/src/mono/wasi/Makefile
+++ /dev/null
@@ -1,51 +0,0 @@
-include Makefile.variable
-
-all: build-all
-
-build-all: $(WASI_SDK_CLANG)
- mkdir -p $(WASI_OBJ_DIR)
- cd $(WASI_OBJ_DIR) && \
- PATH=$(NINJA_DIR):${PATH} cmake -G Ninja \
- -DWASI_SDK_PREFIX=$(WASI_SDK_ROOT) \
- -DCMAKE_SYSROOT=$(WASI_SDK_ROOT)/share/wasi-sysroot \
- -DCMAKE_TOOLCHAIN_FILE=$(WASI_SDK_ROOT)/share/cmake/wasi-sdk.cmake \
- -DCMAKE_C_FLAGS="--sysroot=$(WASI_SDK_ROOT)/share/wasi-sysroot \
- -I$(CURDIR)/include -I$(TOP)/src/mono -I$(TOP)/src/native/public -I$(TOP)/src/mono/mono/eglib -I$(WASI_OBJ_DIR)/mono/eglib -I$(WASI_OBJ_DIR) -I$(TOP)/artifacts/obj/wasm -I$(TOP)/src/mono/wasm/runtime" \
- -DCMAKE_CXX_FLAGS="--sysroot=$(WASI_SDK_ROOT)/share/wasi-sysroot" \
- -DENABLE_MINIMAL=jit,sgen_major_marksweep_conc,sgen_split_nursery,sgen_gc_bridge,sgen_toggleref,sgen_debug_helpers,sgen_binary_protocol,logging,interpreter,threads,qcalls,debugger_agent,sockets,eventpipe \
- -DDISABLE_SHARED_LIBS=1 \
- -Wl,--allow-undefined \
- $(TOP)/src/mono
- cd $(WASI_OBJ_DIR) && PATH=$(NINJA_DIR):${PATH} ninja
-
- mkdir -p $(WASI_BIN_DIR)
- cp $(WASI_OBJ_DIR)/mono/mini/*.a $(WASI_OBJ_DIR)/libmono-wasi-driver.a $(WASI_BIN_DIR)
- rm -rf $(WASI_BIN_DIR)/libmono-component-hot_reload-static.a
- rm -rf $(WASI_BIN_DIR)/libmono-component-diagnostics_tracing-static.a
- mkdir -p $(WASI_BIN_DIR)/include/mono-wasi
- cp mono-wasi-driver/*.h $(WASI_BIN_DIR)/include/mono-wasi
-
-$(WASI_SDK_CLANG):
- mkdir -p $(WASI_OBJ_DIR)
- cd $(WASI_OBJ_DIR) && \
- wget -q https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$(WASI_SDK_VERSION)/wasi-sdk-$(WASI_SDK_VERSION).0-linux.tar.gz && \
- tar xf wasi-sdk-*.tar.gz
-
-.stamp-wasmtime-$(WASMTIME_VERSION):
- @echo "** Provisioning wasmtime $(WASMTIME_VERSION) **"
- rm -Rf $(WASMTIME_DIR) && \
- wget -q https://github.com/bytecodealliance/wasmtime/releases/download/$(WASMTIME_VERSION)/$(WASMTIME_DIR_NAME).tar.xz -O - | tar -C `dirname $(WASMTIME_DIR)` -Jxf - && \
- touch $@
-
-.stamp-ninja-$(NINJA_VERSION):
- @echo "** Provisioning ninja $(NINJA_VERSION) **"
- rm -Rf $(NINJA_DIR); \
- mkdir $(NINJA_DIR) && \
- wget -q https://github.com/ninja-build/ninja/releases/download/v1.11.0/ninja-linux.zip -O $(NINJA_DIR)/ninja.zip && \
- (cd $(NINJA_DIR) && unzip -q ninja.zip && rm ninja.zip) && \
- touch $@
-
-provision-deps: .stamp-wasmtime-$(WASMTIME_VERSION) .stamp-ninja-$(NINJA_VERSION)
- @echo "-------------------------------------------"
- @echo "** Installed wasmtime in $(WASMTIME_DIR)"
- @echo "** Installed ninja in $(NINJA_DIR)"
diff --git a/src/mono/wasi/Makefile.variable b/src/mono/wasi/Makefile.variable
deleted file mode 100644
index ef8b91b245c246..00000000000000
--- a/src/mono/wasi/Makefile.variable
+++ /dev/null
@@ -1,16 +0,0 @@
-TOP=$(realpath $(CURDIR)/../../..)
-CONFIG?=Release
-RUNTIME_CONFIG?=Release
-WASI_SDK_VERSION=12
-
-WASI_OBJ_DIR=$(TOP)/artifacts/obj/mono/Wasi.$(RUNTIME_CONFIG)
-WASI_BIN_DIR=$(TOP)/artifacts/bin/mono/Wasi.$(RUNTIME_CONFIG)
-WASI_SDK_ROOT=$(WASI_OBJ_DIR)/wasi-sdk-$(WASI_SDK_VERSION).0
-WASI_SDK_CLANG=$(WASI_SDK_ROOT)/bin/clang
-
-WASMTIME_VERSION=v0.39.1
-WASMTIME_DIR_NAME=wasmtime-$(WASMTIME_VERSION)-x86_64-linux
-WASMTIME_DIR=$(TOP)/artifacts/bin/$(WASMTIME_DIR_NAME)
-
-NINJA_VERSION=v1.11.0
-NINJA_DIR=$(TOP)/artifacts/bin/ninja
diff --git a/src/mono/wasi/README.md b/src/mono/wasi/README.md
index a44f8d5db93230..66e59384297bb3 100644
--- a/src/mono/wasi/README.md
+++ b/src/mono/wasi/README.md
@@ -8,59 +8,21 @@ The mechanism for executing .NET code in a WASI runtime environment is equivalen
## How to build the runtime
-### 1. Build the WASM runtime
-
-To build the wasi runtime we need the file `wasm_m2n_invoke.g.h` which is generated when compiling wasm runtime
-
-```
-make -C src/mono/wasm provision-wasm
-export EMSDK_PATH=[path_printed_by_provision_wasm]
-./build.sh mono+libs -os browser
-```
-
-### 2. Build the WASI runtime
-
-Currently this can only be built in Linux or WSL (tested on Windows 11). Simply run `make` in this directory. It will automatically download and use [WASI SDK](https://github.com/WebAssembly/wasi-sdk).
-
-The resulting libraries are placed in `(repo_root)/artifacts/bin/mono/Wasi.Release`.
-
-## How to build and run the sample
-
-### 1. Obtain a WASI runtime
-
-To run an application in a WASI environment, you need to have a WASI runtime available. For example, download [wasmtime](https://github.com/bytecodealliance/wasmtime/releases) and make sure it's available on `PATH`:
-
+on Linux:
+```.sh
+./build.sh -bl -os wasi -subset mono+libs -c Debug
```
-export PATH=~/wasmtime-v0.31.0-x86_64-linux
-wasmtime --version
+or for just native rebuild
+```.sh
+./build.sh -bl -os wasi -subset mono.runtime+libs.native+mono.wasiruntime -c Debug
```
-Other WASI runtimes also work. Tested: [wamr](https://github.com/bytecodealliance/wasm-micro-runtime), [wasmer](https://wasmer.io/).
-
-### 2. Obtain a suitable .NET build toolchain
-
-You also need to have a working installation of .NET 7 including the `browser-wasm` runtime pack. For example, obtain the [.NET SDK daily build](https://github.com/dotnet/installer/blob/main/README.md#installers-and-binaries) (`main` branch), and ensure the `browser-wasm` pack is installed:
-
-```
-dotnet workload install wasm-tools -s https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json
-```
-
-To make this available to the build scripts, supply environment variables. Example:
-
-```
-export DOTNET_ROOT=~/dotnet7
-export BROWSER_WASM_RUNTIME_PATH=$(DOTNET_ROOT)/packs/Microsoft.NETCore.App.Runtime.Mono.browser-wasm/7.0.0-alpha.1.22061.11/runtimes/browser-wasm
-```
-
-You'll need to update these paths to match the location where you extracted the .NET daily SDK build and the exact version of the `browser-wasm` pack you received.
-
### 3. Run it
Finally, you can build and run the sample:
```
-cd sample/console
-make run
+./dotnet.sh build /p:TargetOS=wasi /p:Configuration=Debug /t:RunSample src/mono/sample/wasi/console
```
### 4. Debug it
diff --git a/src/mono/wasi/build/WasiApp.InTree.props b/src/mono/wasi/build/WasiApp.InTree.props
new file mode 100644
index 00000000000000..8c119d5413b585
--- /dev/null
+++ b/src/mono/wasi/build/WasiApp.InTree.props
@@ -0,0 +1,2 @@
+
+
diff --git a/src/mono/wasi/build/WasiApp.InTree.targets b/src/mono/wasi/build/WasiApp.InTree.targets
new file mode 100644
index 00000000000000..8c119d5413b585
--- /dev/null
+++ b/src/mono/wasi/build/WasiApp.InTree.targets
@@ -0,0 +1,2 @@
+
+
diff --git a/src/mono/wasi/include/netdb.h b/src/mono/wasi/include/netdb.h
new file mode 100644
index 00000000000000..f905f3bb8cd197
--- /dev/null
+++ b/src/mono/wasi/include/netdb.h
@@ -0,0 +1 @@
+const char *gai_strerror(int);
diff --git a/src/mono/wasi/mono-wasi-driver/driver.h b/src/mono/wasi/mono-include/driver.h
similarity index 95%
rename from src/mono/wasi/mono-wasi-driver/driver.h
rename to src/mono/wasi/mono-include/driver.h
index a27f2b8480614d..664680e137c234 100644
--- a/src/mono/wasi/mono-wasi-driver/driver.h
+++ b/src/mono/wasi/mono-include/driver.h
@@ -13,7 +13,6 @@ MonoClass* mono_wasm_assembly_find_class (MonoAssembly *assembly, const char *na
MonoMethod* mono_wasm_assembly_find_method (MonoClass *klass, const char *name, int arguments);
MonoObject* mono_wasm_invoke_method (MonoMethod *method, MonoObject *this_arg, void *params[], MonoObject **out_exc);
int mono_unbox_int (MonoObject *obj);
-void mono_wasm_setenv (const char *name, const char *value);
void add_assembly(const char* base_dir, const char *name);
MonoArray* mono_wasm_obj_array_new (int size);
diff --git a/src/mono/wasi/mono-include/pinvoke.h b/src/mono/wasi/mono-include/pinvoke.h
new file mode 100644
index 00000000000000..78c30f22693c8d
--- /dev/null
+++ b/src/mono/wasi/mono-include/pinvoke.h
@@ -0,0 +1,52 @@
+// TODOWASI deduplicate src/mono/wasm/runtime/pinvoke.h
+
+#ifndef __PINVOKE_H__
+#define __PINVOKE_H__
+
+#include
+
+typedef struct {
+ const char *name;
+ void *func;
+} PinvokeImport;
+
+typedef struct {
+ void *func;
+ void *arg;
+} InterpFtnDesc;
+
+void*
+wasm_dl_lookup_pinvoke_table (const char *name);
+
+int
+wasm_dl_is_pinvoke_table (void *handle);
+
+void*
+wasm_dl_get_native_to_interp (const char *key, void *extra_arg);
+
+void
+mono_wasm_pinvoke_vararg_stub (void);
+
+typedef void* (*MonoWasmNativeToInterpCallback) (char * cookie);
+
+void
+mono_wasm_install_interp_to_native_callback (MonoWasmNativeToInterpCallback cb);
+
+typedef struct _MonoInterpMethodArguments MonoInterpMethodArguments;
+
+int
+mono_wasm_interp_method_args_get_iarg (MonoInterpMethodArguments *margs, int i);
+
+int64_t
+mono_wasm_interp_method_args_get_larg (MonoInterpMethodArguments *margs, int i);
+
+float
+mono_wasm_interp_method_args_get_farg (MonoInterpMethodArguments *margs, int i);
+
+double
+mono_wasm_interp_method_args_get_darg (MonoInterpMethodArguments *margs, int i);
+
+void*
+mono_wasm_interp_method_args_get_retval (MonoInterpMethodArguments *margs);
+
+#endif
diff --git a/src/mono/wasi/include/pthread.h b/src/mono/wasi/mono-include/pthread.h
similarity index 100%
rename from src/mono/wasi/include/pthread.h
rename to src/mono/wasi/mono-include/pthread.h
diff --git a/src/mono/wasi/include/setjmp.h b/src/mono/wasi/mono-include/setjmp.h
similarity index 100%
rename from src/mono/wasi/include/setjmp.h
rename to src/mono/wasi/mono-include/setjmp.h
diff --git a/src/mono/wasi/mono-include/wasm-config.h.in b/src/mono/wasi/mono-include/wasm-config.h.in
new file mode 100644
index 00000000000000..4c33fd663663c0
--- /dev/null
+++ b/src/mono/wasi/mono-include/wasm-config.h.in
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+#ifndef __MONO_WASM_CONFIG_H__
+#define __MONO_WASM_CONFIG_H__
+
+/* Support for threads is disabled */
+#cmakedefine DISABLE_THREADS
+
+/* Support for starting user threads is disabled */
+#cmakedefine DISABLE_WASM_USER_THREADS
+
+#endif/*__MONO_WASM_CONFIG_H__*/
+
+// TODOWASI deduplicate with src/mono/wasm/runtime/wasm-config.h.in
\ No newline at end of file
diff --git a/src/mono/wasi/provision.ps1 b/src/mono/wasi/provision.ps1
new file mode 100644
index 00000000000000..3d3602f0a901c3
--- /dev/null
+++ b/src/mono/wasi/provision.ps1
@@ -0,0 +1,16 @@
+param(
+ [Parameter()]
+ [string]$WasiSdkUrl,
+ [Parameter()]
+ [string]$WasiSdkVersion,
+ [Parameter()]
+ [string]$WasiSdkPath,
+ [Parameter()]
+ [string]$WasiLocalPath
+)
+
+New-Item -Path $WasiSdkPath -ItemType "directory"
+Invoke-WebRequest -Uri $WasiSdkUrl -OutFile ./wasi-sdk-$WasiSdkVersion.0-mingw.tar.gz
+tar --strip-components=1 -xvzf ./wasi-sdk-$WasiSdkVersion.0-mingw.tar.gz -C $WasiSdkPath
+Copy-Item $WasiLocalPath/wasi-sdk-version.txt $WasiSdkPath/wasi-sdk-version.txt
+Remove-Item ./wasi-sdk-$WasiSdkVersion.0-mingw.tar.gz -fo
diff --git a/src/mono/wasi/runtime/CMakeLists.txt b/src/mono/wasi/runtime/CMakeLists.txt
new file mode 100644
index 00000000000000..8e4114f0c31e45
--- /dev/null
+++ b/src/mono/wasi/runtime/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 3.14.5)
+
+project(mono-wasi-runtime C)
+
+option(DISABLE_THREADS "defined if the build does NOT support multithreading" ON)
+option(DISABLE_WASM_USER_THREADS "defined if the build does not allow user threads to be created in a multithreaded build" OFF)
+
+set(CMAKE_EXECUTABLE_SUFFIX ".wasm")
+add_executable(dotnet driver.c pinvoke.c stubs.c synthetic-pthread.c)
+
+target_include_directories(dotnet PUBLIC ${MONO_INCLUDES} ${MONO_OBJ_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}/include/wasm)
+target_compile_options(dotnet PUBLIC @${NATIVE_BIN_DIR}/src/wasi-default.rsp @${NATIVE_BIN_DIR}/src/wasi-compile.rsp -DCORE_BINDINGS -DGEN_PINVOKE=1)
+
+set_target_properties(dotnet PROPERTIES COMPILE_FLAGS ${CONFIGURATION_WASICC_FLAGS})
+
+target_link_libraries(dotnet
+ #TODOWASI ${ICU_LIB_DIR}/libicuuc.a
+ #TODOWASI ${ICU_LIB_DIR}/libicui18n.a
+ ${MONO_ARTIFACTS_DIR}/libmono-component-hot_reload-static.a
+ ${MONO_ARTIFACTS_DIR}/libmono-component-debugger-static.a
+ ${MONO_ARTIFACTS_DIR}/libmono-component-diagnostics_tracing-stub-static.a
+ ${MONO_ARTIFACTS_DIR}/libmono-component-marshal-ilgen-static.a
+ ${MONO_ARTIFACTS_DIR}/libmono-ee-interp.a
+ ${MONO_ARTIFACTS_DIR}/libmonosgen-2.0.a
+ ${MONO_ARTIFACTS_DIR}/libmono-icall-table.a
+ ${NATIVE_BIN_DIR}/libSystem.Native.a
+ ${NATIVE_BIN_DIR}/libSystem.IO.Compression.Native.a
+)
+
+set_target_properties(dotnet PROPERTIES
+ LINK_DEPENDS "${NATIVE_BIN_DIR}/src/wasi-default.rsp;"
+ LINK_FLAGS "@${NATIVE_BIN_DIR}/src/wasi-default.rsp @${NATIVE_BIN_DIR}/src/wasi-link.rsp ${CONFIGURATION_LINK_FLAGS} "
+ RUNTIME_OUTPUT_DIRECTORY "${NATIVE_BIN_DIR}")
+
+set(ignoreMeWasmOptFlags "${CONFIGURATION_WASM_OPT_FLAGS}${CMAKE_CXX_FLAGS}")
+
+#TODOWASI wasm-opt
+
+configure_file(../mono-include/wasm-config.h.in include/wasm/wasm-config.h)
diff --git a/src/mono/wasi/mono-wasi-driver/driver.c b/src/mono/wasi/runtime/driver.c
similarity index 50%
rename from src/mono/wasi/mono-wasi-driver/driver.c
rename to src/mono/wasi/runtime/driver.c
index df4ef9911429ba..f460a450c0bd31 100644
--- a/src/mono/wasi/mono-wasi-driver/driver.c
+++ b/src/mono/wasi/runtime/driver.c
@@ -8,22 +8,19 @@
#include
#include
#include
-#include
-#include
-#include
#define INVARIANT_GLOBALIZATION 1
+#include
#include
+#include
#include
#include
#include
-#include
#include
+#include
#include
-#include
-#include
-#include
+#include
#include
#include
@@ -33,11 +30,21 @@
#include
#include
-#include "wasm/runtime/pinvoke.h"
+#include "pinvoke.h"
#ifdef GEN_PINVOKE
#include "wasm_m2n_invoke.g.h"
#endif
+#include "../../wasm/runtime/gc-common.h"
+
+
+#if !defined(ENABLE_AOT) || defined(EE_MODE_LLVMONLY_INTERP)
+#define NEED_INTERP 1
+#ifndef LINK_ICALLS
+// FIXME: llvm+interp mode needs this to call icalls
+#define NEED_NORMAL_ICALL_TABLES 1
+#endif
+#endif
void mono_wasm_enable_debugging (int);
@@ -72,11 +79,15 @@ static MonoDomain *root_domain;
#define RUNTIMECONFIG_BIN_FILE "runtimeconfig.bin"
static void
-wasm_trace_logger (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data)
+wasi_trace_logger (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data)
{
- printf("[wasm_trace_logger] %s\n", message);
- if (fatal)
- exit (1);
+ printf("[wasi_trace_logger] %s\n", message);
+ if (fatal) {
+ // make it trap so we could see the stack trace
+ // (*(int*)(void*)-1)++;
+ exit(1);
+ }
+
}
typedef uint32_t target_mword;
@@ -124,43 +135,10 @@ struct WasmSatelliteAssembly_ {
static WasmSatelliteAssembly *satellite_assemblies;
static int satellite_assembly_count;
-int32_t time(int32_t x) {
- // In the current prototype, libSystem.Native.a is built using Emscripten, whereas the WASI-enabled runtime is being built
- // using WASI SDK. Emscripten says that time() returns int32, whereas WASI SDK says it returns int64.
- // TODO: Build libSystem.Native.a using WASI SDK.
- // In the meantime, as a workaround we can define an int32-returning implementation for time() here.
- struct timeval time;
- return (gettimeofday(&time, NULL) == 0) ? time.tv_sec : 0;
-}
-
-typedef struct
-{
- int32_t Flags; // flags for testing if some members are present (see FileStatusFlags)
- int32_t Mode; // file mode (see S_I* constants above for bit values)
- uint32_t Uid; // user ID of owner
- uint32_t Gid; // group ID of owner
- int64_t Size; // total size, in bytes
- int64_t ATime; // time of last access
- int64_t ATimeNsec; // nanosecond part
- int64_t MTime; // time of last modification
- int64_t MTimeNsec; // nanosecond part
- int64_t CTime; // time of last status change
- int64_t CTimeNsec; // nanosecond part
- int64_t BirthTime; // time the file was created
- int64_t BirthTimeNsec; // nanosecond part
- int64_t Dev; // ID of the device containing the file
- int64_t Ino; // inode number of the file
- uint32_t UserFlags; // user defined flags
-} FileStatus;
-
char* gai_strerror(int code) {
- char result[256];
- sprintf(result, "Error code %i", code);
- return result;
-}
-
-int32_t dotnet_browser_entropy(uint8_t* buffer, int32_t bufferLength) {
- return getentropy (buffer, bufferLength);
+ char* result = malloc(256);
+ sprintf(result, "Error code %i", code);
+ return result;
}
void
@@ -173,183 +151,122 @@ mono_wasm_add_satellite_assembly (const char *name, const char *culture, const u
++satellite_assembly_count;
}
-void
-mono_wasm_setenv (const char *name, const char *value)
+static void *sysglobal_native_handle;
+
+static void*
+wasm_dl_load (const char *name, int flags, char **err, void *user_data)
{
- monoeg_g_setenv (strdup (name), strdup (value), 1);
-}
+ void* handle = wasm_dl_lookup_pinvoke_table (name);
+ if (handle)
+ return handle;
-static void *sysglobal_native_handle;
-int32_t SystemNative_LChflagsCanSetHiddenFlag(void);
-char* SystemNative_GetEnv(char* name);
-char* SystemNative_GetEnviron(char* name);
-void SystemNative_FreeEnviron(char* name);
-intptr_t SystemNative_Dup(intptr_t oldfd);
-int32_t SystemNative_Write(intptr_t fd, const void* buffer, int32_t bufferSize);
-int64_t SystemNative_GetSystemTimeAsTicks();
-int32_t SystemNative_Stat(const char* path, void* output);
-int32_t SystemNative_LStat(const char* path, void* output);
-int32_t SystemNative_ConvertErrorPlatformToPal(int32_t platformErrno);
-void* SystemNative_LowLevelMonitor_Create();
-void SystemNative_LowLevelMonitor_Acquire(void* monitor);
-void SystemNative_LowLevelMonitor_Release(void* monitor);
-int32_t SystemNative_LowLevelMonitor_TimedWait(void *monitor, int32_t timeoutMilliseconds);
-void SystemNative_LowLevelMonitor_Wait(void* monitor);
-int SystemNative_GetErrNo();
-void SystemNative_SetErrNo(int value);
-char* SystemNative_GetCwd();
-void SystemNative_GetNonCryptographicallySecureRandomBytes();
-void SystemNative_GetCryptographicallySecureRandomBytes();
-int32_t SystemNative_Open(const char* path, int x, int y);
-void SystemNative_ConvertErrorPalToPlatform();
-void SystemNative_StrErrorR();
-void SystemNative_Close();
-void SystemNative_FStat();
-void SystemNative_LSeek();
-void SystemNative_PRead();
-void SystemNative_CanGetHiddenFlag();
-int32_t SystemNative_Access(const char* path, int32_t mode);
-void SystemNative_Malloc();
-void SystemNative_Free();
-void SystemNative_SysLog();
-
-#define PAL_O_RDONLY 0x0000
-#define PAL_O_WRONLY 0x0001
-#define PAL_O_RDWR 0x0002
-#define PAL_O_ACCESS_MODE_MASK 0x000F
-
-int32_t SystemNative_Open2(const char* path, int flags, int mode) {
- //printf ("In SystemNative_Open2 for %s\n", path);
- // The implementation in libSystemNative tries to use PAL_O_CLOEXEC, which isn't supported here, so override it
- if ((flags & PAL_O_ACCESS_MODE_MASK) == PAL_O_RDONLY) {
- flags = O_RDONLY;
- } else if ((flags & PAL_O_ACCESS_MODE_MASK) == PAL_O_RDWR) {
- flags = O_RDWR;
- } else if ((flags & PAL_O_ACCESS_MODE_MASK) == PAL_O_WRONLY) {
- flags = O_WRONLY;
- }
+ if (!strcmp (name, "System.Globalization.Native"))
+ return sysglobal_native_handle;
- int result;
- while ((result = open(path, flags, (mode_t)mode)) < 0 && errno == EINTR);
- return result;
+#if WASM_SUPPORTS_DLOPEN
+ return dlopen(name, flags);
+#endif
+
+ return NULL;
}
-int32_t SystemNative_Stat2(const char* path, FileStatus* output)
+static void*
+wasm_dl_symbol (void *handle, const char *name, char **err, void *user_data)
{
- // For some reason the libSystemNative SystemNative_Stat doesn't seem to work. Maybe I did something wrong elsewhere,
- // or maybe it's hardcoded to something specific to browser wasm
- struct stat stat_result;
- int ret;
- while ((ret = stat(path, &stat_result)) < 0 && errno == EINTR);
-
- output->Size = stat_result.st_size;
- output->ATime = stat_result.st_atime;
- output->MTime = stat_result.st_mtime;
- output->CTime = stat_result.st_ctime;
- output->Mode = S_ISDIR (stat_result.st_mode)
- ? 0x4000 // Dir
- : 0x8000; // File
-
- // Never fail when looking for the root directory. Even if the WASI host isn't giving us filesystem access
- // (which is the default), we need the root directory to appear to exist, otherwise things like ASP.NET Core
- // will fail by default, whether or not it needs to read anything from the filesystem.
- if (ret != 0 && path[0] == '/' && path[1] == 0) {
- output->Mode = 0x4000; // Dir
- return 0;
- }
+ if (handle == sysglobal_native_handle)
+ assert (0);
- //printf("SystemNative_Stat2 for %s has ISDIR=%i and will return mode %i; ret=%i\n", path, S_ISDIR (stat_result.st_mode), output->Mode, ret);
+#if WASM_SUPPORTS_DLOPEN
+ if (!wasm_dl_is_pinvoke_tables (handle)) {
+ return dlsym (handle, name);
+ }
+#endif
- return ret;
+ PinvokeImport *table = (PinvokeImport*)handle;
+ for (int i = 0; table [i].name; ++i) {
+ if (!strcmp (table [i].name, name))
+ return table [i].func;
+ }
+ return NULL;
}
-int32_t SystemNative_Write2(intptr_t fd, const void* buffer, int32_t bufferSize) {
- // Not sure why, but am getting fd=-1 when trying to write to stdout (which fails), so here's a workaround
- return SystemNative_Write((int)fd == -1 ? 1: fd, buffer, bufferSize);
-}
+#if !defined(ENABLE_AOT) || defined(EE_MODE_LLVMONLY_INTERP)
+#define NEED_INTERP 1
+#ifndef LINK_ICALLS
+// FIXME: llvm+interp mode needs this to call icalls
+#define NEED_NORMAL_ICALL_TABLES 1
+#endif
+#endif
-int64_t SystemNative_GetTimestamp2() {
- // libSystemNative's implementation of SystemNative_GetTimestamp causes the process to exit. It probably
- // relies on calling into JS.
- struct timeval time;
- return (gettimeofday(&time, NULL) == 0)
- ? (int64_t)(time.tv_sec) * 1000000000 + (time.tv_usec * 1000)
- : 0;
-}
+#ifdef LINK_ICALLS
-static PinvokeImport SystemNativeImports [] = {
- {"SystemNative_GetEnv", SystemNative_GetEnv },
- {"SystemNative_GetEnviron", SystemNative_GetEnviron },
- {"SystemNative_FreeEnviron", SystemNative_FreeEnviron },
- {"SystemNative_LChflagsCanSetHiddenFlag", SystemNative_LChflagsCanSetHiddenFlag },
- {"SystemNative_Dup", SystemNative_Dup},
- {"SystemNative_Write", SystemNative_Write2},
- {"SystemNative_GetSystemTimeAsTicks", SystemNative_GetSystemTimeAsTicks},
- {"SystemNative_LStat", SystemNative_Stat2},
- {"SystemNative_FStat", SystemNative_FStat},
- {"SystemNative_LSeek", SystemNative_LSeek},
- {"SystemNative_ConvertErrorPlatformToPal", SystemNative_ConvertErrorPlatformToPal},
- {"SystemNative_LowLevelMonitor_Create", SystemNative_LowLevelMonitor_Create},
- {"SystemNative_LowLevelMonitor_Acquire", SystemNative_LowLevelMonitor_Acquire},
- {"SystemNative_LowLevelMonitor_Release", SystemNative_LowLevelMonitor_Release},
- {"SystemNative_LowLevelMonitor_TimedWait", SystemNative_LowLevelMonitor_TimedWait},
- {"SystemNative_LowLevelMonitor_Wait", SystemNative_LowLevelMonitor_Wait},
- {"SystemNative_GetErrNo", SystemNative_GetErrNo},
- {"SystemNative_SetErrNo", SystemNative_SetErrNo},
- {"SystemNative_GetCwd", SystemNative_GetCwd},
- {"SystemNative_GetNonCryptographicallySecureRandomBytes", SystemNative_GetNonCryptographicallySecureRandomBytes},
- {"SystemNative_GetCryptographicallySecureRandomBytes", SystemNative_GetCryptographicallySecureRandomBytes},
- {"SystemNative_Stat", SystemNative_Stat2},
- {"SystemNative_Open", SystemNative_Open2},
- {"SystemNative_Close", SystemNative_Close},
- {"SystemNative_ConvertErrorPalToPlatform", SystemNative_ConvertErrorPalToPlatform},
- {"SystemNative_StrErrorR", SystemNative_StrErrorR},
- {"SystemNative_PRead", SystemNative_PRead},
- {"SystemNative_CanGetHiddenFlag", SystemNative_CanGetHiddenFlag},
- {"SystemNative_GetTimestamp", SystemNative_GetTimestamp2},
- {"SystemNative_Access", SystemNative_Access},
- {"SystemNative_Malloc", SystemNative_Malloc},
- {"SystemNative_Free", SystemNative_Free},
- {"SystemNative_SysLog", SystemNative_SysLog},
- {NULL, NULL}
-};
+#include "icall-table.h"
-void GlobalizationNative_LoadICU() {
- assert(0);
+static int
+compare_int (const void *k1, const void *k2)
+{
+ return *(int*)k1 - *(int*)k2;
}
-static PinvokeImport SystemGlobalizationNativeImports [] = {
- {"GlobalizationNative_LoadICU", GlobalizationNative_LoadICU },
- {NULL, NULL}
-};
-
static void*
-wasm_dl_load (const char *name, int flags, char **err, void *user_data)
+icall_table_lookup (MonoMethod *method, char *classname, char *methodname, char *sigstart, int32_t *out_flags)
{
- if (!strcmp (name, "libSystem.Native"))
- return SystemNativeImports;
- if (!strcmp (name, "libSystem.Globalization.Native"))
- return SystemGlobalizationNativeImports;
+ uint32_t token = mono_method_get_token (method);
+ assert (token);
+ assert ((token & MONO_TOKEN_METHOD_DEF) == MONO_TOKEN_METHOD_DEF);
+ uint32_t token_idx = token - MONO_TOKEN_METHOD_DEF;
+
+ int *indexes = NULL;
+ int indexes_size = 0;
+ uint8_t *flags = NULL;
+ void **funcs = NULL;
+
+ *out_flags = 0;
+
+ const char *image_name = mono_image_get_name (mono_class_get_image (mono_method_get_class (method)));
+
+#if defined(ICALL_TABLE_corlib)
+ if (!strcmp (image_name, "System.Private.CoreLib")) {
+ indexes = corlib_icall_indexes;
+ indexes_size = sizeof (corlib_icall_indexes) / 4;
+ flags = corlib_icall_flags;
+ funcs = corlib_icall_funcs;
+ assert (sizeof (corlib_icall_indexes [0]) == 4);
+ }
+#endif
+#ifdef ICALL_TABLE_System
+ if (!strcmp (image_name, "System")) {
+ indexes = System_icall_indexes;
+ indexes_size = sizeof (System_icall_indexes) / 4;
+ flags = System_icall_flags;
+ funcs = System_icall_funcs;
+ }
+#endif
+ assert (indexes);
- //printf("In wasm_dl_load for name %s but treating as NOT FOUND\n", name);
- return 0;
+ void *p = bsearch (&token_idx, indexes, indexes_size, 4, compare_int);
+ if (!p) {
+ return NULL;
+ printf ("wasm: Unable to lookup icall: %s\n", mono_method_get_name (method));
+ exit (1);
+ }
+
+ uint32_t idx = (int*)p - indexes;
+ *out_flags = flags [idx];
+
+ //printf ("ICALL: %s %x %d %d\n", methodname, token, idx, (int)(funcs [idx]));
+
+ return funcs [idx];
}
-static void*
-wasm_dl_symbol (void *handle, const char *name, char **err, void *user_data)
+static const char*
+icall_table_lookup_symbol (void *func)
{
- if (handle == sysglobal_native_handle)
- assert (0);
-
- PinvokeImport *table = (PinvokeImport*)handle;
- for (int i = 0; table [i].name; ++i) {
- if (!strcmp (table [i].name, name))
- return table [i].func;
- }
+ assert (0);
return NULL;
}
-#define NEED_INTERP 1
+#endif
/*
* get_native_to_interp:
@@ -361,6 +278,9 @@ wasm_dl_symbol (void *handle, const char *name, char **err, void *user_data)
void*
get_native_to_interp (MonoMethod *method, void *extra_arg)
{
+ void *addr;
+
+ MONO_ENTER_GC_UNSAFE;
MonoClass *klass = mono_method_get_class (method);
MonoImage *image = mono_class_get_image (klass);
MonoAssembly *assembly = mono_image_get_assembly (image);
@@ -379,9 +299,9 @@ get_native_to_interp (MonoMethod *method, void *extra_arg)
key [i] = '_';
}
- assert(0); return 0;
- //void *addr = wasm_dl_get_native_to_interp (key, extra_arg);
- //return addr;
+ addr = wasm_dl_get_native_to_interp (key, extra_arg);
+ MONO_EXIT_GC_UNSAFE;
+ return addr;
}
void
@@ -401,6 +321,8 @@ mono_wasm_register_bundled_satellite_assemblies (void)
}
}
+void mono_wasm_link_icu_shim (void);
+
void
cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data)
{
@@ -409,7 +331,7 @@ cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data)
}
void
-mono_wasm_load_runtime (const char *argv, int debug_level)
+mono_wasm_load_runtime (const char *unused, int debug_level)
{
const char *interp_opts = "";
@@ -421,12 +343,13 @@ mono_wasm_load_runtime (const char *argv, int debug_level)
#ifdef DEBUG
monoeg_g_setenv ("MONO_LOG_LEVEL", "debug", 0);
- monoeg_g_setenv ("MONO_LOG_MASK", "gc", 0);
- // Setting this env var allows Diagnostic.Debug to write to stderr. In a browser environment this
- // output will be sent to the console. Right now this is the only way to emit debug logging from
- // corlib assemblies.
- monoeg_g_setenv ("COMPlus_DebugWriteToStdErr", "1", 0);
+ monoeg_g_setenv ("MONO_LOG_MASK", "all", 0);
+ // Setting this env var allows Diagnostic.Debug to write to stderr. In a browser environment this
+ // output will be sent to the console. Right now this is the only way to emit debug logging from
+ // corlib assemblies.
+ // monoeg_g_setenv ("COMPlus_DebugWriteToStdErr", "1", 0);
#endif
+
char* debugger_fd = monoeg_g_getenv ("DEBUGGER_FD");
if (debugger_fd != 0)
{
@@ -447,7 +370,7 @@ mono_wasm_load_runtime (const char *argv, int debug_level)
const char *appctx_values[2];
appctx_values [0] = "/";
- appctx_values [1] = "browser-wasm";
+ appctx_values [1] = "wasi-wasm";
const char *file_name = RUNTIMECONFIG_BIN_FILE;
int str_len = strlen (file_name) + 1; // +1 is for the "/"
@@ -472,13 +395,53 @@ mono_wasm_load_runtime (const char *argv, int debug_level)
mono_dl_fallback_register (wasm_dl_load, wasm_dl_symbol, NULL, NULL);
mono_wasm_install_get_native_to_interp_tramp (get_native_to_interp);
-
+
#ifdef GEN_PINVOKE
mono_wasm_install_interp_to_native_callback (mono_wasm_interp_to_native_callback);
#endif
+#ifdef ENABLE_AOT
+ monoeg_g_setenv ("MONO_AOT_MODE", "aot", 1);
+
+ // Defined in driver-gen.c
+ register_aot_modules ();
+#ifdef EE_MODE_LLVMONLY_INTERP
+ mono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY_INTERP);
+#else
+ mono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY);
+#endif
+#else
mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP_ONLY);
+ /*
+ * debug_level > 0 enables debugging and sets the debug log level to debug_level
+ * debug_level == 0 disables debugging and enables interpreter optimizations
+ * debug_level < 0 enabled debugging and disables debug logging.
+ *
+ * Note: when debugging is enabled interpreter optimizations are disabled.
+ */
+ if (debug_level) {
+ // Disable optimizations which interfere with debugging
+ interp_opts = "-all";
+ mono_wasm_enable_debugging (debug_level);
+ }
+
+#endif
+
+#ifdef LINK_ICALLS
+ /* Link in our own linked icall table */
+ static const MonoIcallTableCallbacks mono_icall_table_callbacks =
+ {
+ MONO_ICALL_TABLE_CALLBACKS_VERSION,
+ icall_table_lookup,
+ icall_table_lookup_symbol
+ };
+ mono_install_icall_table_callbacks (&mono_icall_table_callbacks);
+#endif
+
+#ifdef NEED_NORMAL_ICALL_TABLES
+ mono_icall_table_init ();
+#endif
mono_ee_interp_init (interp_opts);
mono_marshal_ilgen_init ();
mono_method_builder_ilgen_init ();
@@ -498,7 +461,7 @@ mono_wasm_load_runtime (const char *argv, int debug_level)
mono_wasm_register_bundled_satellite_assemblies ();
mono_trace_init ();
- mono_trace_set_log_handler (wasm_trace_logger, NULL);
+ mono_trace_set_log_handler (wasi_trace_logger, NULL);
root_domain = mono_jit_init_version ("mono", NULL);
mono_thread_set_main (mono_thread_current ());
@@ -507,10 +470,9 @@ mono_wasm_load_runtime (const char *argv, int debug_level)
MonoAssembly*
mono_wasm_assembly_load (const char *name)
{
+ assert (name);
MonoImageOpenStatus status;
MonoAssemblyName* aname = mono_assembly_name_new (name);
- if (!name)
- return NULL;
MonoAssembly *res = mono_assembly_load (aname, NULL, &status);
mono_assembly_name_free (aname);
@@ -518,86 +480,65 @@ mono_wasm_assembly_load (const char *name)
return res;
}
-MonoClass*
-mono_wasm_find_corlib_class (const char *namespace, const char *name)
+MonoAssembly*
+mono_wasm_get_corlib (const char *namespace, const char *name)
{
- return mono_class_from_name (mono_get_corlib (), namespace, name);
+ MonoAssembly* result;
+ MONO_ENTER_GC_UNSAFE;
+ result = mono_image_get_assembly (mono_get_corlib());
+ MONO_EXIT_GC_UNSAFE;
+ return result;
}
MonoClass*
mono_wasm_assembly_find_class (MonoAssembly *assembly, const char *namespace, const char *name)
{
- return mono_class_from_name (mono_assembly_get_image (assembly), namespace, name);
+ assert (assembly);
+ MonoClass *result;
+ MONO_ENTER_GC_UNSAFE;
+ result = mono_class_from_name (mono_assembly_get_image (assembly), namespace, name);
+ MONO_EXIT_GC_UNSAFE;
+ return result;
}
MonoMethod*
mono_wasm_assembly_find_method (MonoClass *klass, const char *name, int arguments)
{
- return mono_class_get_method_from_name (klass, name, arguments);
-}
-
-MonoMethod*
-mono_wasm_get_delegate_invoke (MonoObject *delegate)
-{
- return mono_get_delegate_invoke(mono_object_get_class (delegate));
+ assert (klass);
+ MonoMethod* result;
+ MONO_ENTER_GC_UNSAFE;
+ result = mono_class_get_method_from_name (klass, name, arguments);
+ MONO_EXIT_GC_UNSAFE;
+ return result;
}
-MonoObject*
-mono_wasm_box_primitive (MonoClass *klass, void *value, int value_size)
-{
- if (!klass)
- return NULL;
-
- MonoType *type = mono_class_get_type (klass);
- int alignment;
- if (mono_type_size (type, &alignment) > value_size)
- return NULL;
-
- // TODO: use mono_value_box_checked and propagate error out
- return mono_value_box (root_domain, klass, value);
-}
void
-mono_wasm_invoke_method_ref (MonoMethod *method, MonoObject **this_arg_in, void *params[], MonoObject **out_exc, MonoObject **out_result)
+mono_wasm_invoke_method_ref (MonoMethod *method, MonoObject **this_arg_in, void *params[], MonoObject **_out_exc, MonoObject **out_result)
{
- MonoObject* temp_exc = NULL;
+ PPVOLATILE(MonoObject) out_exc = _out_exc;
+ PVOLATILE(MonoObject) temp_exc = NULL;
if (out_exc)
*out_exc = NULL;
else
out_exc = &temp_exc;
+ MONO_ENTER_GC_UNSAFE;
if (out_result) {
*out_result = NULL;
- *out_result = mono_runtime_invoke (method, this_arg_in ? *this_arg_in : NULL, params, out_exc);
+ PVOLATILE(MonoObject) invoke_result = mono_runtime_invoke (method, this_arg_in ? *this_arg_in : NULL, params, (MonoObject **)out_exc);
+ store_volatile(out_result, invoke_result);
} else {
- mono_runtime_invoke (method, this_arg_in ? *this_arg_in : NULL, params, out_exc);
+ mono_runtime_invoke (method, this_arg_in ? *this_arg_in : NULL, params, (MonoObject **)out_exc);
}
if (*out_exc && out_result) {
- MonoObject *exc2 = NULL;
- *out_result = (MonoObject*)mono_object_to_string (*out_exc, &exc2);
+ PVOLATILE(MonoObject) exc2 = NULL;
+ store_volatile(out_result, (MonoObject*)mono_object_to_string (*out_exc, (MonoObject **)&exc2));
if (exc2)
- *out_result = (MonoObject*) mono_string_new (root_domain, "Exception Double Fault");
- return;
+ store_volatile(out_result, (MonoObject*)mono_string_new (root_domain, "Exception Double Fault"));
}
-}
-
-// deprecated
-MonoObject*
-mono_wasm_invoke_method (MonoMethod *method, MonoObject *this_arg, void *params[], MonoObject **out_exc)
-{
- MonoObject* result = NULL;
- mono_wasm_invoke_method_ref (method, &this_arg, params, out_exc, &result);
-
- MonoMethodSignature *sig = mono_method_signature (method);
- MonoType *type = mono_signature_get_return_type (sig);
- // If the method return type is void return null
- // This gets around a memory access crash when the result return a value when
- // a void method is invoked.
- if (mono_type_get_type (type) == MONO_TYPE_VOID)
- return NULL;
-
- return result;
+ MONO_EXIT_GC_UNSAFE;
}
MonoMethod*
@@ -606,10 +547,11 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly)
MonoImage *image;
MonoMethod *method;
+ MONO_ENTER_GC_UNSAFE;
image = mono_assembly_get_image (assembly);
uint32_t entry = mono_image_get_entry_point (image);
if (!entry)
- return NULL;
+ goto end;
mono_domain_ensure_entry_assembly (root_domain, assembly);
method = mono_get_method (image, entry, NULL);
@@ -626,9 +568,10 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly)
int name_length = strlen (name);
if ((*name != '<') || (name [name_length - 1] != '>'))
- return method;
+ goto end;
MonoClass *klass = mono_method_get_class (method);
+ assert(klass);
char *async_name = malloc (name_length + 2);
snprintf (async_name, name_length + 2, "%s$", name);
@@ -637,7 +580,8 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly)
MonoMethod *async_method = mono_class_get_method_from_name (klass, async_name, mono_signature_get_param_count (sig));
if (async_method != NULL) {
free (async_name);
- return async_method;
+ method = async_method;
+ goto end;
}
// look for "Name" by trimming the first and last character of ""
@@ -646,24 +590,12 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly)
free (async_name);
if (async_method != NULL)
- return async_method;
+ method = async_method;
}
- return method;
-}
-
-char *
-mono_wasm_string_get_utf8 (MonoString *str)
-{
- return mono_string_to_utf8 (str); //XXX JS is responsible for freeing this
-}
-MonoString *
-mono_wasm_string_from_js (const char *str)
-{
- if (str)
- return mono_string_new (root_domain, str);
- else
- return NULL;
+ end:
+ MONO_EXIT_GC_UNSAFE;
+ return method;
}
int
@@ -691,49 +623,18 @@ mono_unbox_int (MonoObject *obj)
return *(unsigned int*)ptr;
case MONO_TYPE_CHAR:
return *(short*)ptr;
- // WASM doesn't support returning longs to JS
- // case MONO_TYPE_I8:
- // case MONO_TYPE_U8:
default:
printf ("Invalid type %d to mono_unbox_int\n", mono_type_get_type (type));
return 0;
}
}
-int
-mono_wasm_array_length (MonoArray *array)
-{
- return mono_array_length (array);
-}
-
-MonoObject*
-mono_wasm_array_get (MonoArray *array, int idx)
-{
- return mono_array_get (array, MonoObject*, idx);
-}
-
-MonoArray*
-mono_wasm_obj_array_new (int size)
-{
- return mono_array_new (root_domain, mono_get_object_class (), size);
-}
-
-void
-mono_wasm_obj_array_set (MonoArray *array, int idx, MonoObject *obj)
-{
- mono_array_setref (array, idx, obj);
-}
-
-MonoArray*
-mono_wasm_string_array_new (int size)
-{
- return mono_array_new (root_domain, mono_get_string_class (), size);
-}
void
mono_wasm_string_get_data_ref (
MonoString **string, mono_unichar2 **outChars, int *outLengthBytes, int *outIsInterned
) {
+ MONO_ENTER_GC_UNSAFE;
if (!string || !(*string)) {
if (outChars)
*outChars = 0;
@@ -741,16 +642,15 @@ mono_wasm_string_get_data_ref (
*outLengthBytes = 0;
if (outIsInterned)
*outIsInterned = 1;
- return;
- }
-
+ } else {
if (outChars)
*outChars = mono_string_chars (*string);
if (outLengthBytes)
*outLengthBytes = mono_string_length (*string) * 2;
if (outIsInterned)
*outIsInterned = mono_string_instance_is_interned (*string);
- return;
+ }
+ MONO_EXIT_GC_UNSAFE;
}
void
@@ -761,36 +661,63 @@ mono_wasm_string_get_data (
}
void add_assembly(const char* base_dir, const char *name) {
- FILE *fileptr;
- unsigned char *buffer;
- long filelen;
- char filename[256];
- sprintf(filename, "%s/%s", base_dir, name);
- // printf("Loading %s...\n", filename);
-
- fileptr = fopen(filename, "rb");
- if (fileptr == 0) {
- printf("Failed to load %s\n", filename);
- fflush(stdout);
- }
-
- fseek(fileptr, 0, SEEK_END);
- filelen = ftell(fileptr);
- rewind(fileptr);
-
- buffer = (unsigned char *)malloc(filelen * sizeof(char));
- fread(buffer, filelen, 1, fileptr);
- fclose(fileptr);
-
- assert(mono_wasm_add_assembly(name, buffer, filelen));
+ FILE *fileptr;
+ unsigned char *buffer;
+ long filelen;
+ char filename[256];
+ sprintf(filename, "%s/%s", base_dir, name);
+ // printf("Loading %s...\n", filename);
+
+ fileptr = fopen(filename, "rb");
+ if (fileptr == 0) {
+ printf("Failed to load %s\n", filename);
+ fflush(stdout);
+ }
+
+ fseek(fileptr, 0, SEEK_END);
+ filelen = ftell(fileptr);
+ rewind(fileptr);
+
+ buffer = (unsigned char *)malloc(filelen * sizeof(char));
+ if(!fread(buffer, filelen, 1, fileptr)) {
+ printf("Failed to load %s\n", filename);
+ fflush(stdout);
+ }
+ fclose(fileptr);
+
+ assert(mono_wasm_add_assembly(name, buffer, filelen));
}
MonoMethod* lookup_dotnet_method(const char* assembly_name, const char* namespace, const char* type_name, const char* method_name, int num_params) {
- MonoAssembly* assembly = mono_wasm_assembly_load (assembly_name);
+ MonoAssembly* assembly = mono_wasm_assembly_load (assembly_name);
assert (assembly);
- MonoClass* class = mono_wasm_assembly_find_class (assembly, namespace, type_name);
+ MonoClass* class = mono_wasm_assembly_find_class (assembly, namespace, type_name);
assert (class);
- MonoMethod* method = mono_wasm_assembly_find_method (class, method_name, num_params);
+ MonoMethod* method = mono_wasm_assembly_find_method (class, method_name, num_params);
assert (method);
return method;
}
+
+int main() {
+ // Assume the runtime pack has been copied into the output directory as 'runtime'
+ // Otherwise we have to mount an unrelated part of the filesystem within the WASM environment
+ mono_set_assemblies_path(".:./runtime/native:./runtime/lib/net8.0");
+ mono_wasm_load_runtime("", 0);
+
+ MonoAssembly* assembly = mono_wasm_assembly_load ("Wasi.Console.Sample");
+ MonoMethod* entry_method = mono_wasm_assembly_get_entry_point (assembly);
+ MonoObject* out_exc;
+ MonoObject* out_res;
+ mono_wasm_invoke_method_ref (entry_method, NULL, NULL, &out_exc, &out_res);
+ if (out_exc)
+ {
+ mono_print_unhandled_exception(out_exc);
+ exit(1);
+ }
+ if(out_res)
+ {
+ int r= mono_unbox_int (out_res);
+ return r;
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/src/mono/wasi/runtime/pinvoke.c b/src/mono/wasi/runtime/pinvoke.c
new file mode 100644
index 00000000000000..0655b256f034dc
--- /dev/null
+++ b/src/mono/wasi/runtime/pinvoke.c
@@ -0,0 +1,64 @@
+// TODOWASI deduplicate src/mono/wasm/runtime/pinvoke.c
+#include "wasm-config.h"
+#include "pinvoke.h"
+
+#include
+#include
+
+/*
+ * The table header contain autogenerated function declarations, so avoid including standard headers
+ * to avoid incompatible declarations.
+ */
+#define NULL ((void*)0)
+int strcmp (const char *s1, const char *s2);
+void mono_wasm_printerr (const char *s);
+
+#ifdef GEN_PINVOKE
+#include "pinvoke-table.h"
+#else
+#include "pinvoke-tables-default.h"
+#endif
+
+void
+mono_wasm_pinvoke_vararg_stub (void)
+{
+ /* This is just a stub used to mark vararg pinvokes */
+}
+
+void*
+wasm_dl_lookup_pinvoke_table (const char *name)
+{
+ for (int i = 0; i < sizeof (pinvoke_tables) / sizeof (void*); ++i) {
+ if (!strcmp (name, pinvoke_names [i]))
+ return pinvoke_tables [i];
+ }
+ return NULL;
+}
+
+int
+wasm_dl_is_pinvoke_table (void *handle)
+{
+ for (int i = 0; i < sizeof (pinvoke_tables) / sizeof (void*); ++i) {
+ if (pinvoke_tables [i] == handle) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void*
+wasm_dl_get_native_to_interp (const char *key, void *extra_arg)
+{
+#ifdef GEN_PINVOKE
+ for (int i = 0; i < sizeof (wasm_native_to_interp_map) / sizeof (void*); ++i) {
+ if (!strcmp (wasm_native_to_interp_map [i], key)) {
+ void *addr = wasm_native_to_interp_funcs [i];
+ wasm_native_to_interp_ftndescs [i] = *(InterpFtnDesc*)extra_arg;
+ return addr;
+ }
+ }
+ return NULL;
+#else
+ return NULL;
+#endif
+}
diff --git a/src/mono/wasi/mono-wasi-driver/stubs.c b/src/mono/wasi/runtime/stubs.c
similarity index 100%
rename from src/mono/wasi/mono-wasi-driver/stubs.c
rename to src/mono/wasi/runtime/stubs.c
diff --git a/src/mono/wasi/mono-wasi-driver/synthetic-pthread.c b/src/mono/wasi/runtime/synthetic-pthread.c
similarity index 100%
rename from src/mono/wasi/mono-wasi-driver/synthetic-pthread.c
rename to src/mono/wasi/runtime/synthetic-pthread.c
diff --git a/src/mono/wasi/sample/.gitignore b/src/mono/wasi/sample/.gitignore
deleted file mode 100644
index 19e1bced9ad8a5..00000000000000
--- a/src/mono/wasi/sample/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.wasm
diff --git a/src/mono/wasi/sample/Directory.Build.props b/src/mono/wasi/sample/Directory.Build.props
deleted file mode 100644
index cd84104a099ad4..00000000000000
--- a/src/mono/wasi/sample/Directory.Build.props
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
- bin/$(Configuration)/$(NetCoreAppCurrent)
-
-
diff --git a/src/mono/wasi/sample/Directory.Build.targets b/src/mono/wasi/sample/Directory.Build.targets
deleted file mode 100644
index fd6cac33af7e80..00000000000000
--- a/src/mono/wasi/sample/Directory.Build.targets
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/src/mono/wasi/sample/SampleMakefile.variable b/src/mono/wasi/sample/SampleMakefile.variable
deleted file mode 100644
index 99f7e6916e9cdc..00000000000000
--- a/src/mono/wasi/sample/SampleMakefile.variable
+++ /dev/null
@@ -1,20 +0,0 @@
-TOP=$(realpath $(CURDIR)/../../../../..)
-
-COMPILE_FLAGS=\
- $(WASI_BIN_DIR)/*.a \
- $(BROWSER_WASM_RUNTIME_PATH)/native/libSystem.Native.a \
- --sysroot=$(WASI_SDK_ROOT)/share/wasi-sysroot \
- -I$(TOP)/src/mono -I$(TOP)/src/native/public
-
-LINK_FLAGS=\
- -Wl,--export=malloc,--export=free,--export=__heap_base,--export=__data_end \
- -Wl,-z,stack-size=1048576,--initial-memory=5242880,--max-memory=52428800,-lwasi-emulated-mman
-
-ifndef DOTNET_ROOT
-DOTNET_ROOT=$(TOP)/.dotnet
-echo "DOTNET_ROOT is undefined. Example: export DOTNET_ROOT=~/dotnet7. Defaulting to $(DOTNET_ROOT)
-endif
-ifndef BROWSER_WASM_RUNTIME_PATH
-BROWSER_WASM_RUNTIME_PATH=$(TOP)/artifacts/bin/microsoft.netcore.app.runtime.browser-wasm/$(CONFIG)/runtimes/browser-wasm
-echo "BROWSER_WASM_RUNTIME_PATH is undefined. Example: export BROWSER_WASM_RUNTIME_PATH=$(DOTNET_ROOT)/packs/Microsoft.NETCore.App.Runtime.Mono.browser-wasm/7.0.0-alpha.1.22061.11/runtimes/browser-wasm). Defaulting to $(BROWSER_WASM_RUNTIME_PATH)"
-endif
diff --git a/src/mono/wasi/sample/console/Makefile b/src/mono/wasi/sample/console/Makefile
deleted file mode 100644
index c05eb4b3cb621c..00000000000000
--- a/src/mono/wasi/sample/console/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-include ../../Makefile.variable
-include ../SampleMakefile.variable
-
-BIN_DIR=WasiConsoleApp/bin/Debug/net8.0
-
-all: console.wasm $(BIN_DIR)/WasiConsoleApp.dll
-
-run: all
- @(which wasmtime || PATH=$(WASMTIME_DIR):${PATH} which wasmtime); \
- test "$$?" -ne 0 \
- && echo "wasmtime not found. Either install that yourself, or use 'make provision-deps' to install one." \
- || PATH=$(WASMTIME_DIR):${PATH} wasmtime --dir=. console.wasm
-
-run-wasmer: all
- wasmer --dir=. console.wasm
-
-console.wasm: main.c
- $(WASI_SDK_CLANG) main.c -o console.wasm $(COMPILE_FLAGS) $(LINK_FLAGS)
-
-$(BIN_DIR)/WasiConsoleApp.dll: WasiConsoleApp/*.csproj WasiConsoleApp/*.cs
- find $(BROWSER_WASM_RUNTIME_PATH) -type f
- cd WasiConsoleApp && $(DOTNET_ROOT)/dotnet build -c Debug
- touch $(BIN_DIR)/*.dll
- cp -R $(BROWSER_WASM_RUNTIME_PATH) $(BIN_DIR)/runtime
-
-debug: all
-#wasmtime has a bug when passing --tcplisten and --dir, to make it work we should use this PR https://github.com/bytecodealliance/wasmtime/pull/3995 and then the fd of the socket will be 4.
- PATH=$(WASMTIME_DIR):${PATH} wasmtime --tcplisten localhost:64000 --dir=. console.wasm --env DEBUGGER_FD=4
diff --git a/src/mono/wasi/sample/console/WasiConsoleApp/Program.cs b/src/mono/wasi/sample/console/WasiConsoleApp/Program.cs
deleted file mode 100644
index 83a7facbcf64d4..00000000000000
--- a/src/mono/wasi/sample/console/WasiConsoleApp/Program.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-
-namespace WasiConsoleApp
-{
- public class Program
- {
- public static int Main()
- {
- Console.WriteLine($"Hello from .NET at {DateTime.Now.ToLongTimeString()}");
- return 0;
- }
- }
-}
diff --git a/src/mono/wasi/sample/console/WasiConsoleApp/WasiConsoleApp.csproj b/src/mono/wasi/sample/console/WasiConsoleApp/WasiConsoleApp.csproj
deleted file mode 100644
index cae907a0c3cf80..00000000000000
--- a/src/mono/wasi/sample/console/WasiConsoleApp/WasiConsoleApp.csproj
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- Exe
- net8.0
- true
- embedded
- false
-
-
-
diff --git a/src/mono/wasi/sample/console/main.c b/src/mono/wasi/sample/console/main.c
deleted file mode 100644
index 10e8ae96c5fef0..00000000000000
--- a/src/mono/wasi/sample/console/main.c
+++ /dev/null
@@ -1,21 +0,0 @@
-#include
-#include "../../mono-wasi-driver/driver.h"
-
-int main() {
- // Assume the runtime pack has been copied into the output directory as 'runtime'
- // Otherwise we have to mount an unrelated part of the filesystem within the WASM environment
- const char* app_base_dir = "./WasiConsoleApp/bin/Debug/net8.0";
- char* assemblies_path;
- asprintf(&assemblies_path, "%s:%s/runtime/native:%s/runtime/lib/net8.0", app_base_dir, app_base_dir, app_base_dir);
-
- add_assembly(app_base_dir, "WasiConsoleApp.dll");
- mono_set_assemblies_path(assemblies_path);
-
- mono_wasm_load_runtime("", 0);
-
- MonoAssembly* assembly = mono_wasm_assembly_load ("WasiConsoleApp.dll");
- MonoMethod* entry_method = mono_wasm_assembly_get_entry_point (assembly);
- MonoObject* out_exc;
- MonoObject *exit_code = mono_wasm_invoke_method (entry_method, NULL, NULL, &out_exc);
- return mono_unbox_int (exit_code);
-}
diff --git a/src/mono/wasi/wasi-sdk-version.txt b/src/mono/wasi/wasi-sdk-version.txt
new file mode 100644
index 00000000000000..19c7bdba7b1e9b
--- /dev/null
+++ b/src/mono/wasi/wasi-sdk-version.txt
@@ -0,0 +1 @@
+16
\ No newline at end of file
diff --git a/src/mono/wasi/wasi.proj b/src/mono/wasi/wasi.proj
index 7053b6b952e0e6..1cdad54d21740f 100644
--- a/src/mono/wasi/wasi.proj
+++ b/src/mono/wasi/wasi.proj
@@ -1,2 +1,245 @@
+
+
+ wasi-wasm
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'native', '$(NetCoreAppCurrent)-$(TargetOS)-$(Configuration)-$(TargetArchitecture)'))
+
+
+
+
+ $([MSBuild]::NormalizeDirectory('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm', 'native', 'lib'))
+ $([MSBuild]::NormalizeDirectory('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm-threads', 'native', 'lib'))
+ false
+ false
+ $(ArtifactsObjDir)wasm
+ <_WasiDefaultsRspPath>$(NativeBinDir)src\wasi-default.rsp
+ <_WasiCompileRspPath>$(NativeBinDir)src\wasi-compile.rsp
+ <_WasiLinkRspPath>$(NativeBinDir)src\wasi-link.rsp
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(NativeBinDir)dotnet.timezones.blat
+
+
+
+
+
+
+
+
+ $(WasmObjDir)\pinvoke-table.h
+ $(WasmObjDir)\wasm_m2n_invoke.g.h
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_WasiFlags Include="@(_WasiCommonFlags)" />
+
+ <_WasiCompileFlags Condition="'$(MonoWasmThreads)' == 'true'" Include="-I$([MSBuild]::NormalizePath('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm-threads', 'native', 'include').Replace('\','/'))"/>
+ <_WasiCompileFlags Condition="'$(MonoWasmThreads)' != 'true'" Include="-I$([MSBuild]::NormalizePath('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm', 'native', 'include').Replace('\','/'))"/>
+ <_WasiCompileFlags Include="-I$([MSBuild]::NormalizePath('$(MonoProjectRoot)', 'wasi', 'include').Replace('\','/'))"/>
+ <_WasiCompileFlags Include="-I$([MSBuild]::NormalizePath('$(MonoProjectRoot)', 'wasi', 'mono-include').Replace('\','/'))"/>
+ <_WasiCompileFlags Include="-I$([MSBuild]::NormalizePath('$(RepoRoot)', 'src', 'native', 'public').Replace('\','/'))"/>
+ <_WasiCompileFlags Include="-I$([MSBuild]::NormalizePath('$(MonoProjectRoot)', 'mono', 'eglib').Replace('\','/'))"/>
+ <_WasiCompileFlags Include="-D_WASI_EMULATED_PROCESS_CLOCKS"/>
+ <_WasiCompileFlags Include="-D_WASI_EMULATED_SIGNAL"/>
+ <_WasiCompileFlags Include="-D_WASI_EMULATED_MMAN"/>
+ <_WasiLinkFlags Include="-Wl,-z,stack-size=1048576,--initial-memory=5242880,--max-memory=52428800,-lwasi-emulated-process-clocks,-lwasi-emulated-signal,-lwasi-emulated-mman"/>
+
+
+
+ <_WasmOptConfigurationFlags>@(WasmOptConfigurationFlags, '%3B ')
+ <_WasiPropsJson>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(ArtifactsObjDir)wasm/pinvoke-table.h
+ $(ArtifactsObjDir)wasm/wasm_m2n_invoke.g.h
+ $([MSBuild]::EnsureTrailingSlash('$(WASI_SDK_PATH)').Replace('\', '/'))
+
+ -g -Os -DDEBUG=1 -DENABLE_AOT_PROFILER=1
+ -Oz
+
+ $(CMakeConfigurationWasiFlags)
+ -O2
+
+ cmake $(MSBuildThisFileDirectory)runtime
+ cmake -G Ninja $(MSBuildThisFileDirectory)runtime
+
+ $(CMakeBuildRuntimeConfigureCmd) -DWASI_SDK_PREFIX=$(WASI_SDK_PATH)
+ $(CMakeBuildRuntimeConfigureCmd) -DCMAKE_SYSROOT=$(WASI_SDK_PATH)share/wasi-sysroot
+ $(CMakeBuildRuntimeConfigureCmd) -DCMAKE_CXX_FLAGS="--sysroot=$(WASI_SDK_PATH)share/wasi-sysroot"
+ $(CMakeBuildRuntimeConfigureCmd) -DCMAKE_TOOLCHAIN_FILE=$(WASI_SDK_PATH)share/cmake/wasi-sdk.cmake
+
+ $(CMakeBuildRuntimeConfigureCmd) -DCONFIGURATION_WASICC_FLAGS="$(CMakeConfigurationWasiFlags)"
+ $(CMakeBuildRuntimeConfigureCmd) -DCONFIGURATION_LINK_FLAGS="$(CMakeConfigurationLinkFlags)"
+ $(CMakeBuildRuntimeConfigureCmd) -DCONFIGURATION_WASM_OPT_FLAGS="@(WasmOptConfigurationFlags, ';')"
+ $(CMakeBuildRuntimeConfigureCmd) -DMONO_INCLUDES="$(MonoArtifactsPath)include/mono-2.0"
+ $(CMakeBuildRuntimeConfigureCmd) -DMONO_OBJ_INCLUDES="$(MonoObjDir.TrimEnd('\/'))"
+
+ $(CMakeBuildRuntimeConfigureCmd) -DMONO_ARTIFACTS_DIR="$(MonoArtifactsPath.TrimEnd('\/'))"
+ $(CMakeBuildRuntimeConfigureCmd) -DNATIVE_BIN_DIR="$(NativeBinDir.TrimEnd('\/'))"
+ $(CMakeBuildRuntimeConfigureCmd) -DWASM_OPT_ADDITIONAL_FLAGS="--enable-simd"
+ $(CMakeBuildRuntimeConfigureCmd) -DDISABLE_THREADS=0
+ $(CMakeBuildRuntimeConfigureCmd) -DDISABLE_WASM_USER_THREADS=1
+ call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" wasm && $(CMakeBuildRuntimeConfigureCmd)
+
+ -v
+ cmake --build . --config $(Configuration) $(CmakeOptions)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mono/wasi/wasmtime-version.txt b/src/mono/wasi/wasmtime-version.txt
new file mode 100644
index 00000000000000..56fea8a08d2faa
--- /dev/null
+++ b/src/mono/wasi/wasmtime-version.txt
@@ -0,0 +1 @@
+3.0.0
\ No newline at end of file
diff --git a/src/mono/wasm/runtime/gc-common.h b/src/mono/wasm/runtime/gc-common.h
index 92789e641a361e..4432633db76459 100644
--- a/src/mono/wasm/runtime/gc-common.h
+++ b/src/mono/wasm/runtime/gc-common.h
@@ -1,6 +1,10 @@
#define PVOLATILE(T) T* volatile
#define PPVOLATILE(T) T* volatile *
+#if !defined(TARGET_BROWSER) && !defined(EMSCRIPTEN_KEEPALIVE)
+#define EMSCRIPTEN_KEEPALIVE
+#endif
+
#define gpointer void*
MONO_API MONO_RT_EXTERNAL_ONLY gpointer
diff --git a/src/native/libs/CMakeLists.txt b/src/native/libs/CMakeLists.txt
index 251473bef8d4d4..6dde2f698bda74 100644
--- a/src/native/libs/CMakeLists.txt
+++ b/src/native/libs/CMakeLists.txt
@@ -35,7 +35,7 @@ else ()
set(STATIC_LIB_DESTINATION .)
endif ()
-if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER)
+if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI)
set(CMAKE_MACOSX_RPATH ON)
if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON)
@@ -48,11 +48,25 @@ if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER)
add_compile_options(-I${CMAKE_CURRENT_SOURCE_DIR}/Common)
add_compile_options(-I${CMAKE_CURRENT_BINARY_DIR}/Common)
- if (CLR_CMAKE_TARGET_BROWSER)
+ if (CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI)
set(GEN_SHARED_LIB 0)
set(STATIC_LIB_DESTINATION .)
endif ()
+ if (CLR_CMAKE_TARGET_WASI)
+ set(HOST_WASI 1)
+ add_compile_options(-I${CLR_REPO_ROOT_DIR}/src/mono/wasi/include/)
+ add_compile_options(-I${CLR_REPO_ROOT_DIR}/src/mono/wasi/libs-include/)
+ add_compile_options(-Wno-unused-variable)
+ add_compile_options(-Wno-unused-parameter)
+ add_compile_options(-Wno-gnu-statement-expression)
+ add_compile_options(-DHOST_WASI)
+ add_compile_options(-D_WASI_EMULATED_PROCESS_CLOCKS)
+ add_compile_options(-D_WASI_EMULATED_SIGNAL)
+ add_compile_options(-D_WASI_EMULATED_MMAN)
+ add_link_options(-Wl,-z,stack-size=1048576,--initial-memory=5242880,--max-memory=52428800,-lwasi-emulated-process-clocks,-lwasi-emulated-signal,-lwasi-emulated-mman)
+ endif ()
+
if (CLR_CMAKE_TARGET_ANDROID)
if (CROSS_ROOTFS)
include_directories(SYSTEM "${CROSS_ROOTFS}/usr/include")
@@ -125,10 +139,10 @@ endif ()
add_subdirectory(System.IO.Compression.Native)
-if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER)
+if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI)
include(configure.cmake)
- if (NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID)
+ if (NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID)
add_subdirectory(System.IO.Ports.Native)
endif ()
@@ -146,7 +160,7 @@ if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER)
add_subdirectory(System.Native)
- if (CLR_CMAKE_TARGET_BROWSER)
+ if (CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI)
# skip for now
elseif (CLR_CMAKE_TARGET_MACCATALYST)
add_subdirectory(System.Net.Security.Native)
diff --git a/src/native/libs/Common/pal_config.h.in b/src/native/libs/Common/pal_config.h.in
index acacfb33e34a3c..7d78597da3861c 100644
--- a/src/native/libs/Common/pal_config.h.in
+++ b/src/native/libs/Common/pal_config.h.in
@@ -8,6 +8,7 @@
#cmakedefine01 HAVE_STATFS_MOUNT
#cmakedefine01 HAVE_FLOCK64
#cmakedefine01 HAVE_F_DUPFD_CLOEXEC
+#cmakedefine01 HAVE_F_DUPFD
#cmakedefine01 HAVE_F_FULLFSYNC
#cmakedefine01 HAVE_O_CLOEXEC
#cmakedefine01 HAVE_GETIFADDRS
@@ -15,6 +16,9 @@
#cmakedefine01 HAVE_STAT64
#cmakedefine01 HAVE_FORK
#cmakedefine01 HAVE_VFORK
+#cmakedefine01 HAVE_CHMOD
+#cmakedefine01 HAVE_FCHMOD
+#cmakedefine01 HAVE_PIPE
#cmakedefine01 HAVE_PIPE2
#cmakedefine01 HAVE_STAT_BIRTHTIME
#cmakedefine01 HAVE_STAT_TIMESPEC
@@ -126,6 +130,12 @@
#cmakedefine01 HAVE_CFSETSPEED
#cmakedefine01 HAVE_CFMAKERAW
#cmakedefine01 HAVE_GETGROUPLIST
+#cmakedefine01 HAVE_SYSLOG_H
+#cmakedefine01 HAVE_TERMIOS_H
+#cmakedefine01 HAVE_DLFCN_H
+#cmakedefine01 HAVE_PTHREAD_H
+#cmakedefine01 HAVE_SYS_STATVFS_H
+#cmakedefine01 HAVE_NET_IF_H
#cmakedefine01 HAVE_SYS_PROCINFO_H
#cmakedefine01 HAVE_IOSS_H
#cmakedefine01 HAVE_ALIGNED_ALLOC
diff --git a/src/native/libs/Common/pal_error_common.h b/src/native/libs/Common/pal_error_common.h
index cf1bb7bcf4b5a1..e9de2b793e4086 100644
--- a/src/native/libs/Common/pal_error_common.h
+++ b/src/native/libs/Common/pal_error_common.h
@@ -309,12 +309,18 @@ inline static int32_t ConvertErrorPlatformToPal(int32_t platformErrno)
case ESOCKTNOSUPPORT:
return Error_ESOCKTNOSUPPORT;
#endif
+#ifdef EPFNOSUPPORT // not available in WASI
case EPFNOSUPPORT:
return Error_EPFNOSUPPORT;
+#endif
+#ifdef ESHUTDOWN // not available in WASI
case ESHUTDOWN:
return Error_ESHUTDOWN;
+#endif
+#ifdef EHOSTDOWN // not available in WASI
case EHOSTDOWN:
return Error_EHOSTDOWN;
+#endif
#ifdef ENODATA // not available in FreeBSD
case ENODATA:
return Error_ENODATA;
@@ -495,16 +501,22 @@ inline static int32_t ConvertErrorPalToPlatform(int32_t error)
return ETXTBSY;
case Error_EXDEV:
return EXDEV;
+#ifdef EPFNOSUPPORT // not available in WASI
case Error_EPFNOSUPPORT:
return EPFNOSUPPORT;
+#endif
#ifdef ESOCKTNOSUPPORT
case Error_ESOCKTNOSUPPORT:
return ESOCKTNOSUPPORT;
#endif
+#ifdef ESHUTDOWN // not available in WASI
case Error_ESHUTDOWN:
return ESHUTDOWN;
+#endif
+#ifdef EHOSTDOWN // not available in WASI
case Error_EHOSTDOWN:
return EHOSTDOWN;
+#endif
#ifdef ENODATA // not available in FreeBSD
case Error_ENODATA:
return ENODATA;
@@ -537,9 +549,11 @@ static bool TryConvertErrorToGai(int32_t error, int32_t* gaiError)
switch (error)
{
+#ifdef EAI_NONAME // not available in WASI
case EHOSTNOTFOUND:
*gaiError = EAI_NONAME;
return true;
+#endif
default:
*gaiError = error;
return false;
diff --git a/src/native/libs/Common/pal_io_common.h b/src/native/libs/Common/pal_io_common.h
index 82a82897444739..75c73b6ef68139 100644
--- a/src/native/libs/Common/pal_io_common.h
+++ b/src/native/libs/Common/pal_io_common.h
@@ -109,9 +109,11 @@ inline static int32_t Common_Poll(PollEvent* pollEvents, uint32_t eventCount, in
case PAL_POLLIN:
pollfds[i].events = POLLIN;
break;
+#ifdef POLLPRI // not available in WASI
case PAL_POLLPRI:
pollfds[i].events = POLLPRI;
break;
+#endif
case PAL_POLLOUT:
pollfds[i].events = POLLOUT;
break;
@@ -157,9 +159,11 @@ inline static int32_t Common_Poll(PollEvent* pollEvents, uint32_t eventCount, in
case POLLIN:
pollEvents[i].TriggeredEvents = PAL_POLLIN;
break;
+#ifdef POLLPRI // not available in WASI
case POLLPRI:
pollEvents[i].TriggeredEvents = PAL_POLLPRI;
break;
+#endif
case POLLOUT:
pollEvents[i].TriggeredEvents = PAL_POLLOUT;
break;
diff --git a/src/native/libs/Common/pal_utilities.h b/src/native/libs/Common/pal_utilities.h
index d517974c9fcf3d..3fece3a08aa3e8 100644
--- a/src/native/libs/Common/pal_utilities.h
+++ b/src/native/libs/Common/pal_utilities.h
@@ -83,7 +83,9 @@ inline static int ToFileDescriptorUnchecked(intptr_t fd)
*/
inline static int ToFileDescriptor(intptr_t fd)
{
+#ifndef TARGET_WASI // the valid range of file descriptors is probably INT32_MIN <= fd && fd <= INT32_MAX, the negative handles are valid for console.
assert(0 <= fd && fd < sysconf(_SC_OPEN_MAX));
+#endif
return ToFileDescriptorUnchecked(fd);
}
diff --git a/src/native/libs/System.Globalization.Native/CMakeLists.txt b/src/native/libs/System.Globalization.Native/CMakeLists.txt
index 5e2fb2948cc436..0ee4e400c5f4ce 100644
--- a/src/native/libs/System.Globalization.Native/CMakeLists.txt
+++ b/src/native/libs/System.Globalization.Native/CMakeLists.txt
@@ -77,11 +77,11 @@ if (CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS
endif()
# time zone names are filtered out of icu data for the browser and associated functionality is disabled
-if (NOT CLR_CMAKE_TARGET_BROWSER)
+if (NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
set(NATIVEGLOBALIZATION_SOURCES ${NATIVEGLOBALIZATION_SOURCES} pal_timeZoneInfo.c)
endif()
-if (NOT GEN_SHARED_LIB AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER)
+if (NOT GEN_SHARED_LIB AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
set(NATIVEGLOBALIZATION_SOURCES ${NATIVEGLOBALIZATION_SOURCES} entrypoints.c)
endif()
diff --git a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt
index a44f847dfca43f..a2fe7605b47eae 100644
--- a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt
+++ b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt
@@ -6,7 +6,7 @@ set(NATIVECOMPRESSION_SOURCES
pal_zlib.c
)
-if (NOT CLR_CMAKE_TARGET_BROWSER)
+if (NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
if (CLR_CMAKE_USE_SYSTEM_BROTLI)
add_definitions(-DFEATURE_USE_SYSTEM_BROTLI)
@@ -25,11 +25,11 @@ if (NOT CLR_CMAKE_TARGET_BROWSER)
)
endif ()
-if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER)
+if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI)
set(NATIVE_LIBS_EXTRA)
append_extra_compression_libs(NATIVE_LIBS_EXTRA)
- if (CLR_CMAKE_TARGET_BROWSER)
+ if (CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI)
include(${CLR_SRC_NATIVE_DIR}/external/zlib.cmake)
add_definitions(-DINTERNAL_ZLIB)
set(NATIVECOMPRESSION_SOURCES ${ZLIB_SOURCES} ${NATIVECOMPRESSION_SOURCES})
@@ -44,7 +44,9 @@ if (CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_BROWSER)
# Delete this suppression once brotli is upgraded to vNext (current latest v1.0.9
# does not contain upstream fix: https://github.com/google/brotli/commit/0a3944c)
- set(FLAGS "${FLAGS} -Wno-vla-parameter")
+ if (NOT CLR_CMAKE_TARGET_WASI)
+ set(FLAGS "${FLAGS} -Wno-vla-parameter")
+ endif ()
set_source_files_properties(${NATIVECOMPRESSION_SOURCES} PROPERTIES COMPILE_FLAGS ${FLAGS})
@@ -118,7 +120,7 @@ else ()
)
endif ()
- if (NOT GEN_SHARED_LIB AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER)
+ if (NOT GEN_SHARED_LIB AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
set(NATIVECOMPRESSION_SOURCES ${NATIVECOMPRESSION_SOURCES} entrypoints.c)
endif ()
diff --git a/src/native/libs/System.IO.Compression.Native/extra_libs.cmake b/src/native/libs/System.IO.Compression.Native/extra_libs.cmake
index b10776372f6cf5..78530ae98e8ff7 100644
--- a/src/native/libs/System.IO.Compression.Native/extra_libs.cmake
+++ b/src/native/libs/System.IO.Compression.Native/extra_libs.cmake
@@ -1,7 +1,7 @@
macro(append_extra_compression_libs NativeLibsExtra)
# TODO: remove the mono-style HOST_ variable checks once Mono is using eng/native/configureplatform.cmake to define the CLR_CMAKE_TARGET_ defines
- if (CLR_CMAKE_TARGET_BROWSER OR HOST_BROWSER)
+ if (CLR_CMAKE_TARGET_BROWSER OR HOST_BROWSER OR CLR_CMAKE_TARGET_WASI OR HOST_WASI)
# nothing special to link
elseif (CLR_CMAKE_TARGET_ANDROID OR HOST_ANDROID)
# need special case here since we want to link against libz.so but find_package() would resolve libz.a
diff --git a/src/native/libs/System.Native/CMakeLists.txt b/src/native/libs/System.Native/CMakeLists.txt
index 61cd36da93b79b..d44823c951354c 100644
--- a/src/native/libs/System.Native/CMakeLists.txt
+++ b/src/native/libs/System.Native/CMakeLists.txt
@@ -1,6 +1,6 @@
project(System.Native C)
-if (NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS)
+if (NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_WASI)
add_definitions(-DHAS_CONSOLE_SIGNALS)
endif ()
@@ -15,28 +15,43 @@ if (CLR_CMAKE_TARGET_OSX)
endif ()
set(NATIVE_SOURCES
- pal_dynamicload.c
pal_errno.c
pal_interfaceaddresses.c
pal_io.c
pal_maphardwaretype.c
pal_memory.c
- pal_mount.c
- pal_networking.c
pal_networkstatistics.c
- pal_process.c
pal_random.c
pal_runtimeinformation.c
- pal_signal.c
pal_string.c
pal_tcpstate.c
- pal_threading.c
pal_time.c
- pal_uid.c
pal_datetime.c
pal_sysctl.c
)
+if (NOT CLR_CMAKE_TARGET_WASI)
+ list (APPEND NATIVE_SOURCES
+ pal_dynamicload.c
+ pal_mount.c
+ pal_networking.c
+ pal_process.c
+ pal_signal.c
+ pal_threading.c
+ pal_uid.c
+ )
+else()
+ list (APPEND NATIVE_SOURCES
+ pal_dynamicload_wasi.c
+ pal_mount_wasi.c
+ pal_networking_wasi.c
+ pal_process_wasi.c
+ pal_signal_wasi.c
+ pal_threading_wasi.c
+ pal_uid_wasi.c
+ )
+endif()
+
if (CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
list (APPEND NATIVE_SOURCES pal_autoreleasepool.m)
set_source_files_properties(pal_autoreleasepool.m PROPERTIES COMPILE_FLAGS -fno-objc-arc)
@@ -64,6 +79,11 @@ elseif (CLR_CMAKE_TARGET_OSX)
pal_searchpath.m
pal_console.c
pal_log.c)
+elseif (CLR_CMAKE_TARGET_WASI)
+ list (APPEND NATIVE_SOURCES
+ pal_searchpath.c
+ pal_console_wasi.c
+ pal_log.c)
else ()
list (APPEND NATIVE_SOURCES
pal_searchpath.c
@@ -79,7 +99,7 @@ else ()
pal_iossupportversion.c)
endif ()
-if (NOT CLR_CMAKE_TARGET_BROWSER)
+if (NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
list (APPEND NATIVE_SOURCES pal_networkchange.c)
endif ()
@@ -107,7 +127,7 @@ if (GEN_SHARED_LIB)
${NATIVE_LIBS_EXTRA}
)
- if (NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER)
+ if (NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
add_custom_command(TARGET System.Native POST_BUILD
COMMENT "Verifying System.Native entry points against entrypoints.c "
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../verify-entrypoints.sh
@@ -121,7 +141,7 @@ if (GEN_SHARED_LIB)
install_with_stripped_symbols (System.Native PROGRAMS .)
endif ()
-if (NOT GEN_SHARED_LIB AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER)
+if (NOT GEN_SHARED_LIB AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
set(NATIVE_SOURCES ${NATIVE_SOURCES} entrypoints.c)
endif()
diff --git a/src/native/libs/System.Native/pal_console_wasi.c b/src/native/libs/System.Native/pal_console_wasi.c
new file mode 100644
index 00000000000000..cb77505bc9a707
--- /dev/null
+++ b/src/native/libs/System.Native/pal_console_wasi.c
@@ -0,0 +1,124 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "pal_config.h"
+#include "pal_console.h"
+#include "pal_utilities.h"
+#include "pal_signal.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef DEBUG
+#define DEBUGNOTRETURN __attribute__((noreturn))
+#else
+#define DEBUGNOTRETURN
+#endif
+
+int32_t SystemNative_GetWindowSize(WinSize* windowSize)
+{
+ assert(windowSize != NULL);
+ memset(windowSize, 0, sizeof(WinSize)); // managed out param must be initialized
+ errno = ENOTSUP;
+ return -1;
+}
+
+int32_t SystemNative_SetWindowSize(WinSize* windowSize)
+{
+ assert(windowSize != NULL);
+ errno = ENOTSUP;
+ return -1;
+}
+
+int32_t SystemNative_IsATty(intptr_t fd)
+{
+ return isatty(ToFileDescriptor(fd));
+}
+
+DEBUGNOTRETURN
+void SystemNative_SetKeypadXmit(const char* terminfoString)
+{
+ assert(terminfoString != NULL);
+ assert_msg(false, "Not supported on WASI", 0);
+}
+
+DEBUGNOTRETURN
+void SystemNative_InitializeConsoleBeforeRead(uint8_t minChars, uint8_t decisecondsTimeout)
+{
+ assert_msg(false, "Not supported on WASI", 0);
+}
+
+DEBUGNOTRETURN
+void SystemNative_UninitializeConsoleAfterRead(void)
+{
+ assert_msg(false, "Not supported on WASI", 0);
+}
+
+DEBUGNOTRETURN
+void SystemNative_ConfigureTerminalForChildProcess(int32_t childUsesTerminal)
+{
+ assert_msg(false, "Not supported on WASI", 0);
+}
+
+DEBUGNOTRETURN
+void SystemNative_GetControlCharacters(
+ int32_t* controlCharacterNames, uint8_t* controlCharacterValues, int32_t controlCharacterLength,
+ uint8_t* posixDisableValue)
+{
+ assert(controlCharacterNames != NULL);
+ assert(controlCharacterValues != NULL);
+ assert(controlCharacterLength >= 0);
+ assert(posixDisableValue != NULL);
+
+ assert_msg(false, "Not supported on WASI", 0);
+}
+
+int32_t SystemNative_StdinReady(void)
+{
+ struct pollfd fd = { .fd = STDIN_FILENO, .events = POLLIN };
+ int rv = poll(&fd, 1, 0) > 0 ? 1 : 0;
+ return rv;
+}
+
+int32_t SystemNative_ReadStdin(void* buffer, int32_t bufferSize)
+{
+ assert(buffer != NULL || bufferSize == 0);
+ assert(bufferSize >= 0);
+
+ if (bufferSize < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ssize_t count;
+ while (CheckInterrupted(count = read(STDIN_FILENO, buffer, Int32ToSizeT(bufferSize))));
+ return (int32_t)count;
+}
+
+int32_t SystemNative_GetSignalForBreak(void)
+{
+ return false;
+}
+
+int32_t SystemNative_SetSignalForBreak(int32_t signalForBreak)
+{
+ assert(signalForBreak == 0 || signalForBreak == 1);
+ assert_msg(false, "Not supported on WASI", 0);
+ return -1;
+}
+
+
+
+int32_t SystemNative_InitializeTerminalAndSignalHandling(void)
+{
+ return true;
+}
diff --git a/src/native/libs/System.Native/pal_dynamicload_wasi.c b/src/native/libs/System.Native/pal_dynamicload_wasi.c
new file mode 100644
index 00000000000000..c4425b8eefbae4
--- /dev/null
+++ b/src/native/libs/System.Native/pal_dynamicload_wasi.c
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "pal_config.h"
+#include "pal_dynamicload.h"
+#include "pal_utilities.h"
+
+#include
+#include
+
+
+void* SystemNative_LoadLibrary(const char* filename)
+{
+ assert_msg(false, "Not supported on WASI", 0);
+ return NULL;
+}
+
+void* SystemNative_GetLoadLibraryError(void)
+{
+ assert_msg(false, "Not supported on WASI", 0);
+ return NULL;
+}
+
+void* SystemNative_GetProcAddress(void* handle, const char* symbol)
+{
+ assert_msg(false, "Not supported on WASI", 0);
+ return NULL;
+}
+
+void SystemNative_FreeLibrary(void* handle)
+{
+}
+
+void* SystemNative_GetDefaultSearchOrderPseudoHandle(void)
+{
+ assert_msg(false, "Not supported on WASI", 0);
+ return NULL;
+}
diff --git a/src/native/libs/System.Native/pal_interfaceaddresses.c b/src/native/libs/System.Native/pal_interfaceaddresses.c
index 4af5d59ae96db9..8fee3e0e3e9649 100644
--- a/src/native/libs/System.Native/pal_interfaceaddresses.c
+++ b/src/native/libs/System.Native/pal_interfaceaddresses.c
@@ -15,11 +15,17 @@
#include
#endif
#ifdef ANDROID_GETIFADDRS_WORKAROUND
+#if HAVE_DLFCN_H
#include
+#endif
+#if HAVE_PTHREAD_H
#include
+#endif
#include "pal_ifaddrs.h" // fallback for Android API 21-23
#endif
+#if HAVE_NET_IF_H
#include
+#endif
#include
#include
#include
@@ -50,6 +56,7 @@
#elif defined(AF_LINK)
#include
#include
+#elif defined(TARGET_WASI)
#else
#error System must have AF_PACKET or AF_LINK.
#endif
@@ -66,6 +73,7 @@
// mask parameter is pointer to buffer where address starts and length is
// buffer length e.g. 4 for IPv4 and 16 for IPv6.
// Code bellow counts consecutive number of 1 bits.
+#if !defined(TARGET_WASI)
static inline uint8_t mask2prefix(uint8_t* mask, int length)
{
uint8_t len = 0;
@@ -101,6 +109,7 @@ static inline uint8_t mask2prefix(uint8_t* mask, int length)
return len;
}
+#endif /* TARGET_WASI */
#ifdef ANDROID_GETIFADDRS_WORKAROUND
// This workaround is necessary as long as we support Android API 21-23 and it can be removed once
diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c
index 0929a0b49ecf42..a0b33a5d43a548 100644
--- a/src/native/libs/System.Native/pal_io.c
+++ b/src/native/libs/System.Native/pal_io.c
@@ -26,8 +26,12 @@
#include
#endif
#include
+#if HAVE_SYSLOG_H
#include
+#endif
+#if HAVE_TERMIOS_H
#include
+#endif
#include
#include
#if HAVE_FCOPYFILE
@@ -42,7 +46,7 @@
#include
#elif HAVE_STATFS_MOUNT // BSD
#include
-#elif !HAVE_NON_LEGACY_STATFS // SunOS
+#elif HAVE_SYS_STATVFS_H && !HAVE_NON_LEGACY_STATFS // SunOS
#include
#include
#include
@@ -70,7 +74,7 @@ extern int getpeereid(int, uid_t *__restrict__, gid_t *__restrict__);
// Ensure FICLONE is defined for all Linux builds.
#ifndef FICLONE
#define FICLONE _IOW(0x94, 9, int)
-#endif
+#endif /* __linux__ */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreserved-id-macro"
@@ -97,11 +101,11 @@ extern int getpeereid(int, uid_t *__restrict__, gid_t *__restrict__);
#define stat_ stat64
#define fstat_ fstat64
#define lstat_ lstat64
-#else
+#else /* HAVE_STAT64 */
#define stat_ stat
#define fstat_ fstat
#define lstat_ lstat
-#endif
+#endif /* HAVE_STAT64 */
// These numeric values are specified by POSIX.
// Validate that our definitions match.
@@ -124,8 +128,10 @@ c_static_assert(PAL_S_ISGID == S_ISGID);
// are common to our current targets. If these static asserts fail,
// ConvertFileStatus needs to be updated to twiddle mode bits
// accordingly.
+#if !defined(TARGET_WASI)
c_static_assert(PAL_S_IFMT == S_IFMT);
c_static_assert(PAL_S_IFIFO == S_IFIFO);
+#endif /* TARGET_WASI */
c_static_assert(PAL_S_IFBLK == S_IFBLK);
c_static_assert(PAL_S_IFCHR == S_IFCHR);
c_static_assert(PAL_S_IFDIR == S_IFDIR);
@@ -139,7 +145,7 @@ c_static_assert(PAL_S_IFSOCK == S_IFSOCK);
// WebAssembly (BROWSER) has dirent d_type but is not correct
// by returning UNKNOWN the managed code properly stats the file
// to detect if entry is directory or not.
-#if defined(DT_UNKNOWN) || defined(TARGET_WASM)
+#if (defined(DT_UNKNOWN) || defined(TARGET_WASM)) && !defined(TARGET_WASI)
c_static_assert((int)PAL_DT_UNKNOWN == (int)DT_UNKNOWN);
c_static_assert((int)PAL_DT_FIFO == (int)DT_FIFO);
c_static_assert((int)PAL_DT_CHR == (int)DT_CHR);
@@ -341,10 +347,14 @@ intptr_t SystemNative_Dup(intptr_t oldfd)
int result;
#if HAVE_F_DUPFD_CLOEXEC
while ((result = fcntl(ToFileDescriptor(oldfd), F_DUPFD_CLOEXEC, 0)) < 0 && errno == EINTR);
-#else
+#elif HAVE_F_DUPFD
while ((result = fcntl(ToFileDescriptor(oldfd), F_DUPFD, 0)) < 0 && errno == EINTR);
// do CLOEXEC here too
fcntl(result, F_SETFD, FD_CLOEXEC);
+#else
+ // The main use cases for dup are setting up the classic Unix dance of setting up file descriptors in advance of performing a fork. Since WASI has no fork, these don't apply.
+ // https://github.com/bytecodealliance/wasmtime/blob/b2fefe77148582a9b8013e34fe5808ada82b6efc/docs/WASI-rationale.md#why-no-dup
+ result = oldfd;
#endif
return result;
}
@@ -570,7 +580,7 @@ int32_t SystemNative_Pipe(int32_t pipeFds[2], int32_t flags)
#if HAVE_PIPE2
// If pipe2 is available, use it. This will handle O_CLOEXEC if it was set.
while ((result = pipe2(pipeFds, flags)) < 0 && errno == EINTR);
-#else
+#elif HAVE_PIPE
// Otherwise, use pipe.
while ((result = pipe(pipeFds)) < 0 && errno == EINTR);
@@ -595,7 +605,9 @@ int32_t SystemNative_Pipe(int32_t pipeFds[2], int32_t flags)
errno = tmpErrno;
}
}
-#endif
+#else /* HAVE_PIPE */
+ result = -1;
+#endif /* HAVE_PIPE */
return result;
}
@@ -695,16 +707,28 @@ int32_t SystemNative_MkDir(const char* path, int32_t mode)
int32_t SystemNative_ChMod(const char* path, int32_t mode)
{
+#if HAVE_CHMOD
int32_t result;
while ((result = chmod(path, (mode_t)mode)) < 0 && errno == EINTR);
return result;
+#else /* HAVE_CHMOD */
+ (void)path; // unused
+ (void)mode; // unused
+ return EINTR;
+#endif /* HAVE_CHMOD */
}
int32_t SystemNative_FChMod(intptr_t fd, int32_t mode)
{
+#if HAVE_FCHMOD
int32_t result;
while ((result = fchmod(ToFileDescriptor(fd), (mode_t)mode)) < 0 && errno == EINTR);
return result;
+#else /* HAVE_FCHMOD */
+ (void)fd; // unused
+ (void)mode; // unused
+ return EINTR;
+#endif /* HAVE_FCHMOD */
}
int32_t SystemNative_FSync(intptr_t fd)
@@ -725,7 +749,11 @@ int32_t SystemNative_FSync(intptr_t fd)
int32_t SystemNative_FLock(intptr_t fd, int32_t operation)
{
int32_t result;
+#if !defined(TARGET_WASI)
while ((result = flock(ToFileDescriptor(fd), operation)) < 0 && errno == EINTR);
+#else /* TARGET_WASI */
+ result = EINTR;
+#endif /* TARGET_WASI */
return result;
}
@@ -748,12 +776,15 @@ int64_t SystemNative_LSeek(intptr_t fd, int64_t offset, int32_t whence)
result =
#if HAVE_LSEEK64
lseek64(
+ ToFileDescriptor(fd),
+ (off_t)offset,
+ whence)) < 0 && errno == EINTR);
#else
lseek(
-#endif
ToFileDescriptor(fd),
(off_t)offset,
whence)) < 0 && errno == EINTR);
+#endif
return result;
}
@@ -773,32 +804,50 @@ int32_t SystemNative_SymLink(const char* target, const char* linkPath)
void SystemNative_GetDeviceIdentifiers(uint64_t dev, uint32_t* majorNumber, uint32_t* minorNumber)
{
+#if !defined(TARGET_WASI)
dev_t castedDev = (dev_t)dev;
*majorNumber = (uint32_t)major(castedDev);
*minorNumber = (uint32_t)minor(castedDev);
+#else /* TARGET_WASI */
+ dev_t castedDev = (dev_t)dev;
+ *majorNumber = 0;
+ *minorNumber = 0;
+#endif /* TARGET_WASI */
}
int32_t SystemNative_MkNod(const char* pathName, uint32_t mode, uint32_t major, uint32_t minor)
{
+#if !defined(TARGET_WASI)
dev_t dev = (dev_t)makedev(major, minor);
int32_t result;
while ((result = mknod(pathName, (mode_t)mode, dev)) < 0 && errno == EINTR);
return result;
+#else /* TARGET_WASI */
+ return EINTR;
+#endif /* TARGET_WASI */
}
int32_t SystemNative_MkFifo(const char* pathName, uint32_t mode)
{
+#if !defined(TARGET_WASI)
int32_t result;
while ((result = mkfifo(pathName, (mode_t)mode)) < 0 && errno == EINTR);
return result;
+#else /* TARGET_WASI */
+ return EINTR;
+#endif /* TARGET_WASI */
}
char* SystemNative_MkdTemp(char* pathTemplate)
{
+#if !defined(TARGET_WASI)
char* result = NULL;
while ((result = mkdtemp(pathTemplate)) == NULL && errno == EINTR);
return result;
+#else /* TARGET_WASI */
+ return NULL;
+#endif /* TARGET_WASI */
}
intptr_t SystemNative_MksTemps(char* pathTemplate, int32_t suffixLength)
@@ -840,6 +889,9 @@ intptr_t SystemNative_MksTemps(char* pathTemplate, int32_t suffixLength)
{
pathTemplate[firstSuffixIndex] = firstSuffixChar;
}
+#elif TARGET_WASI
+ assert_msg(false, "Not supported on WASI", 0);
+ result = -1;
#else
#error "Cannot find mkstemps nor mkstemp on this platform"
#endif
@@ -976,7 +1028,7 @@ int32_t SystemNative_MAdvise(void* address, uint64_t length, int32_t advice)
switch (advice)
{
case PAL_MADV_DONTFORK:
-#ifdef MADV_DONTFORK
+#if defined(MADV_DONTFORK) && !defined(TARGET_WASI)
return madvise(address, (size_t)length, MADV_DONTFORK);
#else
(void)address, (void)length, (void)advice;
@@ -1005,7 +1057,11 @@ int32_t SystemNative_MSync(void* address, uint64_t length, int32_t flags)
return -1;
}
+#if !defined(TARGET_WASI)
return msync(address, (size_t)length, flags);
+#else
+ return -1;
+#endif
}
int64_t SystemNative_SysConf(int32_t name)
@@ -1145,7 +1201,9 @@ int32_t SystemNative_RmDir(const char* path)
void SystemNative_Sync(void)
{
+#if !defined(TARGET_WASI)
sync();
+#endif /* TARGET_WASI */
}
int32_t SystemNative_Write(intptr_t fd, const void* buffer, int32_t bufferSize)
@@ -1369,6 +1427,7 @@ int32_t SystemNative_CopyFile(intptr_t sourceFd, intptr_t destinationFd, int64_t
return -1;
}
+#if HAVE_FCHMOD
// Copy permissions.
// Even though managed code created the file with permissions matching those of the source file,
// we need to copy permissions because the open permissions may be filtered by 'umask'.
@@ -1377,6 +1436,7 @@ int32_t SystemNative_CopyFile(intptr_t sourceFd, intptr_t destinationFd, int64_t
{
return -1;
}
+#endif /* HAVE_FCHMOD */
return 0;
#endif // HAVE_FCOPYFILE
@@ -1458,9 +1518,14 @@ int32_t SystemNative_GetPeerID(intptr_t socket, uid_t* euid)
char* SystemNative_RealPath(const char* path)
{
assert(path != NULL);
+#if !defined(TARGET_WASI)
return realpath(path, NULL);
+#else /* TARGET_WASI */
+ return NULL;
+#endif /* TARGET_WASI */
}
+#if !defined(TARGET_WASI)
static int16_t ConvertLockType(int16_t managedLockType)
{
// the managed enum Interop.Sys.LockType has no 1:1 mapping with corresponding Unix values
@@ -1614,6 +1679,7 @@ static uint32_t MapFileSystemNameToEnum(const char* fileSystemName)
return result;
}
#endif
+#endif /* TARGET_WASI */
uint32_t SystemNative_GetFileSystemType(intptr_t fd)
{
@@ -1634,6 +1700,8 @@ uint32_t SystemNative_GetFileSystemType(intptr_t fd)
uint32_t result = (uint32_t)statfsArgs.f_type;
return result;
#endif
+#elif defined(TARGET_WASI)
+ return EINTR;
#elif !HAVE_NON_LEGACY_STATFS
int statfsRes;
struct statvfs statfsArgs;
@@ -1648,6 +1716,7 @@ uint32_t SystemNative_GetFileSystemType(intptr_t fd)
int32_t SystemNative_LockFileRegion(intptr_t fd, int64_t offset, int64_t length, int16_t lockType)
{
+#if !defined(TARGET_WASI)
int16_t unixLockType = ConvertLockType(lockType);
if (offset < 0 || length < 0)
{
@@ -1677,6 +1746,9 @@ int32_t SystemNative_LockFileRegion(intptr_t fd, int64_t offset, int64_t length,
int32_t ret;
while ((ret = fcntl (ToFileDescriptor(fd), command, &lockArgs)) < 0 && errno == EINTR);
return ret;
+#else /* TARGET_WASI */
+ return EINTR;
+#endif /* TARGET_WASI */
}
int32_t SystemNative_LChflags(const char* path, uint32_t flags)
diff --git a/src/native/libs/System.Native/pal_maphardwaretype.c b/src/native/libs/System.Native/pal_maphardwaretype.c
index 064d802e6d6a83..2a9e78216074ae 100644
--- a/src/native/libs/System.Native/pal_maphardwaretype.c
+++ b/src/native/libs/System.Native/pal_maphardwaretype.c
@@ -21,6 +21,7 @@
#elif defined(AF_LINK)
#include
#include
+#elif defined(TARGET_WASI)
#else
#error System must have AF_PACKET or AF_LINK.
#endif
@@ -112,5 +113,7 @@ uint16_t MapHardwareType(uint16_t nativeType)
default:
return NetworkInterfaceType_Unknown;
}
+#elif defined(TARGET_WASI)
+ return NetworkInterfaceType_Unknown;
#endif
}
diff --git a/src/native/libs/System.Native/pal_mount_wasi.c b/src/native/libs/System.Native/pal_mount_wasi.c
new file mode 100644
index 00000000000000..61b776160eace6
--- /dev/null
+++ b/src/native/libs/System.Native/pal_mount_wasi.c
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "pal_config.h"
+#include "pal_mount.h"
+#include "pal_utilities.h"
+#include
+#include
+#include
+#include
+
+int32_t SystemNative_GetAllMountPoints(MountPointFound onFound, void* context)
+{
+ return -1;
+}
+
+int32_t SystemNative_GetSpaceInfoForMountPoint(const char* name, MountPointInformation* mpi)
+{
+ assert(name != NULL);
+ assert(mpi != NULL);
+ return -1;
+}
+
+int32_t
+SystemNative_GetFormatInfoForMountPoint(const char* name, char* formatNameBuffer, int32_t bufferLength, int64_t* formatType)
+{
+ assert((formatNameBuffer != NULL) && (formatType != NULL));
+ assert(bufferLength > 0);
+ return -1;
+}
diff --git a/src/native/libs/System.Native/pal_networking_wasi.c b/src/native/libs/System.Native/pal_networking_wasi.c
new file mode 100644
index 00000000000000..3cad50780daecb
--- /dev/null
+++ b/src/native/libs/System.Native/pal_networking_wasi.c
@@ -0,0 +1,449 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "pal_config.h"
+#include "pal_networking.h"
+#include "pal_safecrt.h"
+#include "pal_utilities.h"
+#include
+#include
+
+#include
+#include
+int32_t SystemNative_GetHostEntryForName(const uint8_t* address, int32_t addressFamily, HostEntry* entry)
+{
+ return -1;
+}
+
+void SystemNative_FreeHostEntry(HostEntry* entry)
+{
+ if (entry != NULL)
+ {
+ free(entry->CanonicalName);
+ free(entry->IPAddressList);
+
+ entry->CanonicalName = NULL;
+ entry->IPAddressList = NULL;
+ entry->IPAddressCount = 0;
+ }
+}
+
+int32_t SystemNative_GetNameInfo(const uint8_t* address,
+ int32_t addressLength,
+ int8_t isIPv6,
+ uint8_t* host,
+ int32_t hostLength,
+ uint8_t* service,
+ int32_t serviceLength,
+ int32_t flags)
+{
+ assert(address != NULL);
+ assert(addressLength > 0);
+ assert((host != NULL) || (service != NULL));
+ assert((hostLength > 0) || (serviceLength > 0));
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_GetDomainName(uint8_t* name, int32_t nameLength)
+{
+ assert(name != NULL);
+ assert(nameLength > 0);
+ return Error_EFAULT;
+}
+
+int32_t SystemNative_GetHostName(uint8_t* name, int32_t nameLength)
+{
+ assert(name != NULL);
+ assert(nameLength > 0);
+
+ size_t unsignedSize = (uint32_t)nameLength;
+ return gethostname((char*)name, unsignedSize);
+}
+
+int32_t SystemNative_GetIPSocketAddressSizes(int32_t* ipv4SocketAddressSize, int32_t* ipv6SocketAddressSize)
+{
+ return Error_EFAULT;
+}
+
+int32_t SystemNative_GetAddressFamily(const uint8_t* socketAddress, int32_t socketAddressLen, int32_t* addressFamily)
+{
+ return Error_EFAULT;
+}
+
+int32_t SystemNative_SetAddressFamily(uint8_t* socketAddress, int32_t socketAddressLen, int32_t addressFamily)
+{
+ return Error_EFAULT;
+}
+
+int32_t SystemNative_GetPort(const uint8_t* socketAddress, int32_t socketAddressLen, uint16_t* port)
+{
+ return Error_EFAULT;
+}
+
+int32_t SystemNative_SetPort(uint8_t* socketAddress, int32_t socketAddressLen, uint16_t port)
+{
+ return Error_EFAULT;
+}
+
+int32_t SystemNative_GetIPv4Address(const uint8_t* socketAddress, int32_t socketAddressLen, uint32_t* address)
+{
+ return Error_EFAULT;
+}
+
+int32_t SystemNative_SetIPv4Address(uint8_t* socketAddress, int32_t socketAddressLen, uint32_t address)
+{
+ return Error_EFAULT;
+}
+
+int32_t SystemNative_GetIPv6Address(
+ const uint8_t* socketAddress, int32_t socketAddressLen, uint8_t* address, int32_t addressLen, uint32_t* scopeId)
+{
+ return Error_EFAULT;
+}
+
+int32_t
+SystemNative_SetIPv6Address(uint8_t* socketAddress, int32_t socketAddressLen, uint8_t* address, int32_t addressLen, uint32_t scopeId)
+{
+ return Error_EFAULT;
+}
+
+int32_t SystemNative_GetControlMessageBufferSize(int32_t isIPv4, int32_t isIPv6)
+{
+ return Error_EFAULT;
+}
+
+
+int32_t
+SystemNative_TryGetIPPacketInformation(MessageHeader* messageHeader, int32_t isIPv4, IPPacketInformation* packetInfo)
+{
+ if (messageHeader == NULL || packetInfo == NULL)
+ {
+ return 0;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_GetIPv4MulticastOption(intptr_t socket, int32_t multicastOption, IPv4MulticastOption* option)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_SetIPv4MulticastOption(intptr_t socket, int32_t multicastOption, IPv4MulticastOption* option)
+{
+ if (option == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_GetIPv6MulticastOption(intptr_t socket, int32_t multicastOption, IPv6MulticastOption* option)
+{
+ if (option == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_SetIPv6MulticastOption(intptr_t socket, int32_t multicastOption, IPv6MulticastOption* option)
+{
+ if (option == NULL)
+ {
+ return Error_EFAULT;
+ }
+ return Error_EINVAL;
+}
+
+
+int32_t SystemNative_GetLingerOption(intptr_t socket, LingerOption* option)
+{
+ if (option == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_SetLingerOption(intptr_t socket, LingerOption* option)
+{
+ if (option == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_SetReceiveTimeout(intptr_t socket, int32_t millisecondsTimeout)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_SetSendTimeout(intptr_t socket, int32_t millisecondsTimeout)
+{
+ return Error_EINVAL;
+}
+int32_t SystemNative_Receive(intptr_t socket, void* buffer, int32_t bufferLen, int32_t flags, int32_t* received)
+{
+ if (buffer == NULL || bufferLen < 0 || received == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_ReceiveMessage(intptr_t socket, MessageHeader* messageHeader, int32_t flags, int64_t* received)
+{
+ if (messageHeader == NULL || received == NULL || messageHeader->SocketAddressLen < 0 ||
+ messageHeader->ControlBufferLen < 0 || messageHeader->IOVectorCount < 0)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_Send(intptr_t socket, void* buffer, int32_t bufferLen, int32_t flags, int32_t* sent)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_SendMessage(intptr_t socket, MessageHeader* messageHeader, int32_t flags, int64_t* sent)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_Accept(intptr_t socket, uint8_t* socketAddress, int32_t* socketAddressLen, intptr_t* acceptedSocket)
+{
+ if (socketAddress == NULL || socketAddressLen == NULL || acceptedSocket == NULL || *socketAddressLen < 0)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_Bind(intptr_t socket, int32_t protocolType, uint8_t* socketAddress, int32_t socketAddressLen)
+{
+ if (socketAddress == NULL || socketAddressLen < 0)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_Connect(intptr_t socket, uint8_t* socketAddress, int32_t socketAddressLen)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_GetPeerName(intptr_t socket, uint8_t* socketAddress, int32_t* socketAddressLen)
+{
+ if (socketAddress == NULL || socketAddressLen == NULL || *socketAddressLen < 0)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_GetSockName(intptr_t socket, uint8_t* socketAddress, int32_t* socketAddressLen)
+{
+ if (socketAddress == NULL || socketAddressLen == NULL || *socketAddressLen < 0)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_Listen(intptr_t socket, int32_t backlog)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_Shutdown(intptr_t socket, int32_t socketShutdown)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_GetSocketErrorOption(intptr_t socket, int32_t* error)
+{
+ if (error == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_GetSockOpt(
+ intptr_t socket, int32_t socketOptionLevel, int32_t socketOptionName, uint8_t* optionValue, int32_t* optionLen)
+{
+ if (optionLen == NULL || *optionLen < 0)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_GetRawSockOpt(
+ intptr_t socket, int32_t socketOptionLevel, int32_t socketOptionName, uint8_t* optionValue, int32_t* optionLen)
+{
+ if (optionLen == NULL || *optionLen < 0)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t
+SystemNative_SetSockOpt(intptr_t socket, int32_t socketOptionLevel, int32_t socketOptionName, uint8_t* optionValue, int32_t optionLen)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_SetRawSockOpt(
+ intptr_t socket, int32_t socketOptionLevel, int32_t socketOptionName, uint8_t* optionValue, int32_t optionLen)
+{
+ if (optionLen < 0 || optionValue == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_Socket(int32_t addressFamily, int32_t socketType, int32_t protocolType, intptr_t* createdSocket)
+{
+ if (createdSocket == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_GetSocketType(intptr_t socket, int32_t* addressFamily, int32_t* socketType, int32_t* protocolType, int32_t* isListening)
+{
+ if (addressFamily == NULL || socketType == NULL || protocolType == NULL || isListening == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_GetAtOutOfBandMark(intptr_t socket, int32_t* atMark)
+{
+ if (atMark == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_GetBytesAvailable(intptr_t socket, int32_t* available)
+{
+ if (available == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_CreateSocketEventPort(intptr_t* port)
+{
+ if (port == NULL)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_CloseSocketEventPort(intptr_t port)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_CreateSocketEventBuffer(int32_t count, SocketEvent** buffer)
+{
+ if (buffer == NULL || count < 0)
+ {
+ return Error_EFAULT;
+ }
+
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_FreeSocketEventBuffer(SocketEvent* buffer)
+{
+ free(buffer);
+ return Error_SUCCESS;
+}
+
+int32_t
+SystemNative_TryChangeSocketEventRegistration(intptr_t port, intptr_t socket, int32_t currentEvents, int32_t newEvents, uintptr_t data)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_WaitForSocketEvents(intptr_t port, SocketEvent* buffer, int32_t* count)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_PlatformSupportsDualModeIPv4PacketInfo(void)
+{
+ return 0;
+}
+
+
+char* SystemNative_GetPeerUserName(intptr_t socket)
+{
+ return NULL;
+}
+
+void SystemNative_GetDomainSocketSizes(int32_t* pathOffset, int32_t* pathSize, int32_t* addressSize)
+{
+ *pathOffset = -1;
+ *pathSize = -1;
+ *addressSize = -1;
+}
+
+int32_t SystemNative_GetMaximumAddressSize(void)
+{
+ return sizeof(struct sockaddr_storage);
+}
+
+int32_t SystemNative_Disconnect(intptr_t socket)
+{
+ return Error_EINVAL;
+}
+
+int32_t SystemNative_SendFile(intptr_t out_fd, intptr_t in_fd, int64_t offset, int64_t count, int64_t* sent)
+{
+ assert(sent != NULL);
+
+ return Error_EINVAL;
+}
+
+uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName)
+{
+ assert(interfaceName != NULL);
+ return Error_EINVAL;
+}
+
diff --git a/src/native/libs/System.Native/pal_networkstatistics.c b/src/native/libs/System.Native/pal_networkstatistics.c
index 987a0a80d81596..eeeb8ac802942f 100644
--- a/src/native/libs/System.Native/pal_networkstatistics.c
+++ b/src/native/libs/System.Native/pal_networkstatistics.c
@@ -32,7 +32,9 @@
#else
#include
#endif
+#if HAVE_NET_IF_H
#include
+#endif
#include
#include
diff --git a/src/native/libs/System.Native/pal_process_wasi.c b/src/native/libs/System.Native/pal_process_wasi.c
new file mode 100644
index 00000000000000..1d3d6f998ec4e2
--- /dev/null
+++ b/src/native/libs/System.Native/pal_process_wasi.c
@@ -0,0 +1,134 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "pal_config.h"
+#include "pal_process.h"
+#include "pal_io.h"
+#include "pal_utilities.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#ifdef DEBUG
+#define DEBUGNOTRETURN __attribute__((noreturn))
+#else
+#define DEBUGNOTRETURN
+#endif
+
+int32_t SystemNative_ForkAndExecProcess(const char* filename,
+ char* const argv[],
+ char* const envp[],
+ const char* cwd,
+ int32_t redirectStdin,
+ int32_t redirectStdout,
+ int32_t redirectStderr,
+ int32_t setCredentials,
+ uint32_t userId,
+ uint32_t groupId,
+ uint32_t* groups,
+ int32_t groupsLength,
+ int32_t* childPid,
+ int32_t* stdinFd,
+ int32_t* stdoutFd,
+ int32_t* stderrFd)
+{
+ return -1;
+}
+
+int32_t SystemNative_GetRLimit(RLimitResources resourceType, RLimit* limits)
+{
+ assert(limits != NULL);
+ int result = -1;
+ memset(limits, 0, sizeof(RLimit));
+ return result;
+}
+
+int32_t SystemNative_SetRLimit(RLimitResources resourceType, const RLimit* limits)
+{
+ assert(limits != NULL);
+ return -1;
+}
+
+int32_t SystemNative_Kill(int32_t pid, int32_t signal)
+{
+ return -1;
+}
+
+int32_t SystemNative_GetPid(void)
+{
+ return -1;
+}
+
+int32_t SystemNative_GetSid(int32_t pid)
+{
+ return -1;
+}
+
+DEBUGNOTRETURN
+void SystemNative_SysLog(SysLogPriority priority, const char* message, const char* arg1)
+{
+ assert_msg(false, "Not supported on WASI", 0);
+}
+
+int32_t SystemNative_WaitIdAnyExitedNoHangNoWait(void)
+{
+ return -1;
+}
+
+int32_t SystemNative_WaitPidExitedNoHang(int32_t pid, int32_t* exitCode)
+{
+ return -1;
+}
+
+int64_t SystemNative_PathConf(const char* path, PathConfName name)
+{
+ return -1;
+}
+
+int32_t SystemNative_GetPriority(PriorityWhich which, int32_t who)
+{
+ return -1;
+}
+
+int32_t SystemNative_SetPriority(PriorityWhich which, int32_t who, int32_t nice)
+{
+ return -1;
+}
+
+char* SystemNative_GetCwd(char* buffer, int32_t bufferSize)
+{
+ assert(bufferSize >= 0);
+
+ if (bufferSize < 0)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return getcwd(buffer, Int32ToSizeT(bufferSize));
+}
+
+int32_t SystemNative_SchedSetAffinity(int32_t pid, intptr_t* mask)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+int32_t SystemNative_SchedGetAffinity(int32_t pid, intptr_t* mask)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+char* SystemNative_GetProcessPath(void)
+{
+ return minipal_getexepath();
+}
diff --git a/src/native/libs/System.Native/pal_signal_wasi.c b/src/native/libs/System.Native/pal_signal_wasi.c
new file mode 100644
index 00000000000000..71b23867388841
--- /dev/null
+++ b/src/native/libs/System.Native/pal_signal_wasi.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "pal_config.h"
+#include "pal_console.h"
+#include "pal_signal.h"
+#include "pal_io.h"
+#include "pal_utilities.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef DEBUG
+#define DEBUGNOTRETURN __attribute__((noreturn))
+#else
+#define DEBUGNOTRETURN
+#endif
+
+DEBUGNOTRETURN
+void SystemNative_SetPosixSignalHandler(PosixSignalHandler signalHandler)
+{
+ assert(signalHandler);
+ assert_msg(false, "Not supported on WASI", 0);
+}
+
+DEBUGNOTRETURN
+void SystemNative_HandleNonCanceledPosixSignal(int32_t signalCode)
+{
+ assert_msg(false, "Not supported on WASI", 0);
+}
+
+
+DEBUGNOTRETURN
+void SystemNative_SetTerminalInvalidationHandler(TerminalInvalidationCallback callback)
+{
+ assert(callback != NULL);
+ assert_msg(false, "Not supported on WASI", 0);
+}
+
+DEBUGNOTRETURN
+void SystemNative_RegisterForSigChld(SigChldCallback callback)
+{
+ assert(callback != NULL);
+ assert_msg(false, "Not supported on WASI", 0);
+}
+
+DEBUGNOTRETURN
+void SystemNative_SetDelayedSigChildConsoleConfigurationHandler(void (*callback)(void))
+{
+ assert(callback == NULL);
+ assert_msg(false, "Not supported on WASI", 0);
+}
+
+int32_t SystemNative_EnablePosixSignalHandling(int signalCode)
+{
+ return false;
+}
+
+void SystemNative_DisablePosixSignalHandling(int signalCode)
+{
+}
diff --git a/src/native/libs/System.Native/pal_threading_wasi.c b/src/native/libs/System.Native/pal_threading_wasi.c
new file mode 100644
index 00000000000000..1f82d256ef7ac8
--- /dev/null
+++ b/src/native/libs/System.Native/pal_threading_wasi.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "pal_config.h"
+#include "pal_threading.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef DEBUG
+#define DEBUGNOTRETURN __attribute__((noreturn))
+#else
+#define DEBUGNOTRETURN
+#endif
+
+struct LowLevelMonitor
+{
+ bool Dummy;
+};
+
+LowLevelMonitor* SystemNative_LowLevelMonitor_Create(void)
+{
+ return (LowLevelMonitor *)malloc(sizeof(LowLevelMonitor));
+}
+
+void SystemNative_LowLevelMonitor_Destroy(LowLevelMonitor* monitor)
+{
+ assert(monitor != NULL);
+ free(monitor);
+}
+
+void SystemNative_LowLevelMonitor_Acquire(LowLevelMonitor* monitor)
+{
+ assert(monitor != NULL);
+}
+
+void SystemNative_LowLevelMonitor_Release(LowLevelMonitor* monitor)
+{
+ assert(monitor != NULL);
+}
+
+void SystemNative_LowLevelMonitor_Wait(LowLevelMonitor* monitor)
+{
+ assert(monitor != NULL);
+}
+
+int32_t SystemNative_LowLevelMonitor_TimedWait(LowLevelMonitor *monitor, int32_t timeoutMilliseconds)
+{
+ assert(timeoutMilliseconds >= 0);
+ return true;
+}
+
+void SystemNative_LowLevelMonitor_Signal_Release(LowLevelMonitor* monitor)
+{
+ assert(monitor != NULL);
+}
+
+int32_t SystemNative_CreateThread(uintptr_t stackSize, void *(*startAddress)(void*), void *parameter)
+{
+ return false;
+}
+
+int32_t SystemNative_SchedGetCpu(void)
+{
+ return -1;
+}
+
+DEBUGNOTRETURN
+void SystemNative_Exit(int32_t exitCode)
+{
+ exit(exitCode);
+}
+
+DEBUGNOTRETURN
+void SystemNative_Abort(void)
+{
+ abort();
+}
diff --git a/src/native/libs/System.Native/pal_uid_wasi.c b/src/native/libs/System.Native/pal_uid_wasi.c
new file mode 100644
index 00000000000000..1cf93b13d1f4bd
--- /dev/null
+++ b/src/native/libs/System.Native/pal_uid_wasi.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "pal_config.h"
+#include "pal_safecrt.h"
+#include "pal_uid.h"
+#include "pal_utilities.h"
+
+#include
+#include
+#include
+#include
+#include
+
+
+int32_t SystemNative_GetPwUidR(uint32_t uid, Passwd* pwd, char* buf, int32_t buflen)
+{
+ assert(pwd != NULL);
+ assert(buf != NULL);
+ assert(buflen >= 0);
+
+ return EINVAL;
+}
+
+int32_t SystemNative_GetPwNamR(const char* name, Passwd* pwd, char* buf, int32_t buflen)
+{
+ assert(pwd != NULL);
+ assert(buf != NULL);
+ assert(buflen >= 0);
+
+ return EINVAL;
+}
+
+uint32_t SystemNative_GetEUid(void)
+{
+ return EINVAL;
+}
+
+uint32_t SystemNative_GetEGid(void)
+{
+ return EINVAL;
+}
+
+int32_t SystemNative_SetEUid(uint32_t euid)
+{
+ return EINVAL;
+}
+int32_t SystemNative_GetGroupList(const char* name, uint32_t group, uint32_t* groups, int32_t* ngroups)
+{
+ assert(name != NULL);
+ assert(groups != NULL);
+ assert(ngroups != NULL);
+ assert(*ngroups >= 0);
+ return EINVAL;
+}
+
+int32_t SystemNative_GetGroups(int32_t ngroups, uint32_t* groups)
+{
+ assert(ngroups >= 0);
+ assert(groups != NULL);
+
+ return EINVAL;
+}
+
+char* SystemNative_GetGroupName(uint32_t gid)
+{
+ return NULL;
+}
diff --git a/src/native/libs/System.Net.Security.Native/CMakeLists.txt b/src/native/libs/System.Net.Security.Native/CMakeLists.txt
index 6fbe18f76872ef..50c9228fe3dd34 100644
--- a/src/native/libs/System.Net.Security.Native/CMakeLists.txt
+++ b/src/native/libs/System.Net.Security.Native/CMakeLists.txt
@@ -19,7 +19,7 @@ if (GEN_SHARED_LIB)
)
endif()
-if (NOT GEN_SHARED_LIB AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER)
+if (NOT GEN_SHARED_LIB AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
set(NATIVEGSS_SOURCES ${NATIVEGSS_SOURCES} entrypoints.c)
endif()
@@ -35,7 +35,7 @@ if (GEN_SHARED_LIB)
${NATIVE_LIBS_EXTRA}
)
- if (NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER)
+ if (NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
add_custom_command(TARGET System.Net.Security.Native POST_BUILD
COMMENT "Verifying System.Net.Security.Native entry points against entrypoints.c "
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../verify-entrypoints.sh
diff --git a/src/native/libs/build-native.sh b/src/native/libs/build-native.sh
index e6d7f312ee90cf..39e0c59c5b31c0 100755
--- a/src/native/libs/build-native.sh
+++ b/src/native/libs/build-native.sh
@@ -52,11 +52,20 @@ if [[ "$__TargetOS" == Browser ]]; then
fi
fi
source "$EMSDK_PATH"/emsdk_env.sh
-
export CLR_CC=$(which emcc)
elif [[ "$__TargetOS" == wasi ]]; then
- # nothing to do here
- true
+ if [[ -z "$WASI_SDK_PATH" ]]; then
+ if [[ -d "$__RepoRootDir"/src/mono/wasi/wasi-sdk/ ]]; then
+ export WASI_SDK_PATH="$__RepoRootDir"/src/mono/wasi/wasi-sdk/
+ else
+ echo "Error: You need to set the WASI_SDK_PATH environment variable pointing to the WASI SDK root."
+ exit 1
+ fi
+ fi
+ export WASI_SDK_PATH="${WASI_SDK_PATH%/}/"
+ export CLR_CC="$WASI_SDK_PATH"bin/clang
+ export TARGET_BUILD_ARCH=wasm
+ __CMakeArgs="-DCLR_CMAKE_TARGET_OS=WASI -DCLR_CMAKE_TARGET_ARCH=wasm -DWASI_SDK_PREFIX=$WASI_SDK_PATH -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk.cmake"
elif [[ "$__TargetOS" == iOS || "$__TargetOS" == iOSSimulator ]]; then
# nothing to do here
true
diff --git a/src/native/libs/configure.cmake b/src/native/libs/configure.cmake
index 7c5b88e96d5d0f..87a4b430e4a10f 100644
--- a/src/native/libs/configure.cmake
+++ b/src/native/libs/configure.cmake
@@ -131,6 +131,11 @@ check_symbol_exists(
fcntl.h
HAVE_F_DUPFD_CLOEXEC)
+check_symbol_exists(
+ F_DUPFD
+ fcntl.h
+ HAVE_F_DUPFD)
+
check_symbol_exists(
F_FULLFSYNC
fcntl.h
@@ -175,6 +180,11 @@ check_symbol_exists(
unistd.h
HAVE_VFORK)
+check_symbol_exists(
+ pipe
+ unistd.h
+ HAVE_PIPE)
+
check_symbol_exists(
pipe2
unistd.h
@@ -367,6 +377,16 @@ check_symbol_exists(
${STATFS_INCLUDES}
HAVE_STATFS)
+check_symbol_exists(
+ "getrlimit"
+ "sys/resource.h"
+ HAVE_GETRLIMIT)
+
+check_symbol_exists(
+ "setrlimit"
+ "sys/resource.h"
+ HAVE_SETRLIMIT)
+
check_type_size(
"struct statfs"
STATFS_SIZE
@@ -577,7 +597,7 @@ elseif(CLR_CMAKE_TARGET_ANDROID)
unset(HAVE_ALIGNED_ALLOC) # only exists on newer Android
set(HAVE_CLOCK_MONOTONIC 1)
set(HAVE_CLOCK_REALTIME 1)
-elseif(CLR_CMAKE_TARGET_BROWSER)
+elseif(CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI)
set(HAVE_FORK 0)
else()
if(CLR_CMAKE_TARGET_OSX)
@@ -661,7 +681,9 @@ elseif (HAVE_PTHREAD_IN_LIBC)
set(PTHREAD_LIBRARY c)
endif()
-check_library_exists(${PTHREAD_LIBRARY} pthread_condattr_setclock "" HAVE_PTHREAD_CONDATTR_SETCLOCK)
+if (NOT CLR_CMAKE_TARGET_WASI)
+ check_library_exists(${PTHREAD_LIBRARY} pthread_condattr_setclock "" HAVE_PTHREAD_CONDATTR_SETCLOCK)
+endif()
check_symbol_exists(
futimes
@@ -673,6 +695,16 @@ check_symbol_exists(
sys/stat.h
HAVE_FUTIMENS)
+check_symbol_exists(
+ fchmod
+ sys/stat.h
+ HAVE_FCHMOD)
+
+check_symbol_exists(
+ chmod
+ sys/stat.h
+ HAVE_CHMOD)
+
check_symbol_exists(
utimensat
sys/stat.h
@@ -784,7 +816,7 @@ check_c_source_compiles(
"
HAVE_MKSTEMP)
-if (NOT HAVE_MKSTEMPS AND NOT HAVE_MKSTEMP)
+if (NOT HAVE_MKSTEMPS AND NOT HAVE_MKSTEMP AND NOT CLR_CMAKE_TARGET_WASI)
message(FATAL_ERROR "Cannot find mkstemps nor mkstemp on this platform.")
endif()
@@ -872,6 +904,30 @@ check_symbol_exists(
"unistd.h;grp.h"
HAVE_GETGROUPLIST)
+check_include_files(
+ "syslog.h"
+ HAVE_SYSLOG_H)
+
+check_include_files(
+ "termios.h"
+ HAVE_TERMIOS_H)
+
+check_include_files(
+ "dlfcn.h"
+ HAVE_DLFCN_H)
+
+check_include_files(
+ "sys/statvfs.h"
+ HAVE_SYS_STATVFS_H)
+
+check_include_files(
+ "net/if.h"
+ HAVE_NET_IF_H)
+
+check_include_files(
+ "pthread.h"
+ HAVE_PTHREAD_H)
+
if(CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
set(HAVE_IOS_NET_ROUTE_H 1)
set(HAVE_IOS_NET_IFMEDIA_H 1)
@@ -1007,7 +1063,7 @@ set (CMAKE_REQUIRED_LIBRARIES ${PREVIOUS_CMAKE_REQUIRED_LIBRARIES})
set (HAVE_INOTIFY 0)
if (HAVE_INOTIFY_INIT AND HAVE_INOTIFY_ADD_WATCH AND HAVE_INOTIFY_RM_WATCH)
set (HAVE_INOTIFY 1)
-elseif (CLR_CMAKE_TARGET_LINUX AND NOT CLR_CMAKE_TARGET_BROWSER)
+elseif (CLR_CMAKE_TARGET_LINUX AND NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI)
message(FATAL_ERROR "Cannot find inotify functions on a Linux platform.")
endif()
@@ -1092,7 +1148,7 @@ check_symbol_exists(
sys/sysmacros.h
HAVE_MAKEDEV_SYSMACROSH)
-if (NOT HAVE_MAKEDEV_FILEH AND NOT HAVE_MAKEDEV_SYSMACROSH)
+if (NOT HAVE_MAKEDEV_FILEH AND NOT HAVE_MAKEDEV_SYSMACROSH AND NOT CLR_CMAKE_TARGET_WASI)
message(FATAL_ERROR "Cannot find the makedev function on this platform.")
endif()