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()