diff --git a/src/libraries/Common/src/Interop/OSX/System.Native/Interop.Log.cs b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.Log.cs new file mode 100644 index 0000000000000..f6674b988d70e --- /dev/null +++ b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.Log.cs @@ -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. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Sys + { + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Log")] + internal static extern unsafe bool Log(byte* buffer, int count); + } +} diff --git a/src/libraries/Native/Unix/System.Native/CMakeLists.txt b/src/libraries/Native/Unix/System.Native/CMakeLists.txt index e491a59ae97aa..7bf8031bcb616 100644 --- a/src/libraries/Native/Unix/System.Native/CMakeLists.txt +++ b/src/libraries/Native/Unix/System.Native/CMakeLists.txt @@ -1,7 +1,6 @@ project(System.Native C) set(NATIVE_SOURCES - pal_console.c pal_errno.c pal_interfaceaddresses.c pal_io.c @@ -23,6 +22,12 @@ set(NATIVE_SOURCES pal_sysctl.c ) +if (CLR_CMAKE_TARGET_IOS) + set(NATIVE_SOURCES ${NATIVE_SOURCES} pal_log.m) +else () + set(NATIVE_SOURCES ${NATIVE_SOURCES} pal_console.c) +endif () + if (CLR_CMAKE_TARGET_LINUX) set(NATIVE_SOURCES ${NATIVE_SOURCES} pal_networkchange.c) @@ -62,6 +67,10 @@ add_library(System.Native-Static ${NATIVE_SOURCES} ) +if (CLR_CMAKE_TARGET_IOS) + target_link_libraries(System.Native "-framework Foundation") +endif () + set_target_properties(System.Native-Static PROPERTIES OUTPUT_NAME System.Native CLEAN_DIRECT_OUTPUT 1) install (TARGETS System.Native-Static DESTINATION .) diff --git a/src/libraries/Native/Unix/System.Native/pal_log.h b/src/libraries/Native/Unix/System.Native/pal_log.h new file mode 100644 index 0000000000000..bf6f680ce375c --- /dev/null +++ b/src/libraries/Native/Unix/System.Native/pal_log.h @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +#include "pal_compiler.h" +#include "pal_types.h" + +PALEXPORT void SystemNative_Log(uint8_t* buffer, int32_t length); + +// Called by pal_signal.cpp to reinitialize the console on SIGCONT/SIGCHLD. +void ReinitializeTerminal(void) {} +void UninitializeTerminal(void) {} \ No newline at end of file diff --git a/src/libraries/Native/Unix/System.Native/pal_log.m b/src/libraries/Native/Unix/System.Native/pal_log.m new file mode 100644 index 0000000000000..e63bf4e8bd83a --- /dev/null +++ b/src/libraries/Native/Unix/System.Native/pal_log.m @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "pal_log.h" +#import + +void SystemNative_Log (uint8_t* buffer, int32_t length) +{ + NSString *msg = [[NSString alloc] initWithBytes: buffer length: length encoding: NSUTF16LittleEndianStringEncoding]; + if (length > 4096) + { + // Write in chunks of max 4096 characters; older versions of iOS seems to have a bug where NSLog may hang with long strings (!). + // https://github.com/xamarin/maccore/issues/1014 + const char* utf8 = [msg UTF8String]; + size_t len = utf8 == NULL ? 0 : strlen (utf8); + const size_t max_size = 4096; + while (len > 0) + { + size_t chunk_size = len > max_size ? max_size : len; + + // Try to not break in the middle of a line, by looking backwards for a newline + while (chunk_size > 0 && utf8 [chunk_size] != 0 && utf8 [chunk_size] != '\n') + { + chunk_size--; + } + if (chunk_size == 0) + { + // No newline found, break in the middle. + chunk_size = len > max_size ? max_size : len; + } + NSLog (@"%.*s", (int) chunk_size, utf8); + len -= chunk_size; + utf8 += chunk_size; + } + } + else + { + NSLog (@"%@", msg); + } + [msg release]; +} \ No newline at end of file diff --git a/src/libraries/System.Console/src/System.Console.csproj b/src/libraries/System.Console/src/System.Console.csproj index c24b37c5cfb1d..39c094f262172 100644 --- a/src/libraries/System.Console/src/System.Console.csproj +++ b/src/libraries/System.Console/src/System.Console.csproj @@ -3,7 +3,7 @@ System.Console System.Console true - $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix + $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-iOS enable @@ -21,6 +21,16 @@ Common\System\Text\ConsoleEncoding.cs + + + + + Common\Interop\OSX\Interop.Log.cs + + + Common\Interop\Unix\Interop.Libraries.cs + + @@ -164,7 +174,7 @@ - + diff --git a/src/libraries/System.Console/src/System/ConsolePal.iOS.cs b/src/libraries/System.Console/src/System/ConsolePal.iOS.cs new file mode 100644 index 0000000000000..1815beb8fe6a8 --- /dev/null +++ b/src/libraries/System.Console/src/System/ConsolePal.iOS.cs @@ -0,0 +1,170 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Text; + +namespace System +{ + internal sealed class NSLogStream : ConsoleStream + { + public NSLogStream() : base(FileAccess.Write) {} + + public override int Read(byte[] buffer, int offset, int count) => throw Error.GetReadNotSupported(); + + public override unsafe void Write(byte[] buffer, int offset, int count) + { + ValidateWrite(buffer, offset, count); + + fixed (byte* ptr = buffer) + { + Interop.Sys.Log(ptr + offset, count); + } + } + } + + internal static class ConsolePal + { + public static Stream OpenStandardInput() => throw new PlatformNotSupportedException(); + + public static Stream OpenStandardOutput() => new NSLogStream(); + + public static Stream OpenStandardError() => new NSLogStream(); + + public static Encoding InputEncoding => throw new PlatformNotSupportedException(); + + public static void SetConsoleInputEncoding(Encoding enc) => throw new PlatformNotSupportedException(); + + public static Encoding OutputEncoding => Encoding.Unicode; + + // underlying API expects only utf-16 + public static void SetConsoleOutputEncoding(Encoding enc) => throw new PlatformNotSupportedException(); + + public static bool IsInputRedirectedCore() => false; + + public static bool IsOutputRedirectedCore() => false; + + public static bool IsErrorRedirectedCore() => false; + + internal static TextReader GetOrCreateReader() => throw new PlatformNotSupportedException(); + + public static bool NumberLock => false; + + public static bool CapsLock => false; + + 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 BackgroundColor + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static ConsoleColor ForegroundColor + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static void ResetColor() => throw new PlatformNotSupportedException(); + + public static int CursorSize + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static bool CursorVisible + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int CursorLeft => throw new PlatformNotSupportedException(); + + public static int CursorTop => 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 Beep(int frequency, int duration) => 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 Clear() => throw new PlatformNotSupportedException(); + + public static void SetCursorPosition(int left, int top) => throw new PlatformNotSupportedException(); + + public static int BufferWidth + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int BufferHeight + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static void SetBufferSize(int width, int height) => throw new PlatformNotSupportedException(); + + public static int LargestWindowWidth => throw new PlatformNotSupportedException(); + + public static int LargestWindowHeight => throw new PlatformNotSupportedException(); + + public static int WindowLeft + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int WindowTop + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int WindowWidth + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int WindowHeight + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static void SetWindowPosition(int left, int top) => throw new PlatformNotSupportedException(); + + public static void SetWindowSize(int width, int height) => throw new PlatformNotSupportedException(); + + internal sealed class ControlCHandlerRegistrar + { + internal ControlCHandlerRegistrar() => throw new PlatformNotSupportedException(); + + internal void Register() => throw new PlatformNotSupportedException(); + + internal void Unregister() => throw new PlatformNotSupportedException(); + } + } +} \ No newline at end of file diff --git a/src/mono/netcore/sample/iOS/Makefile b/src/mono/netcore/sample/iOS/Makefile index f2cbc1b36edc4..f5f4930045977 100644 --- a/src/mono/netcore/sample/iOS/Makefile +++ b/src/mono/netcore/sample/iOS/Makefile @@ -9,22 +9,25 @@ ARTIFACTS_MONO=$(ARTIFACTS_BIN)/mono/iOS.$(MONO_ARCH).$(MONO_CONFIG) DOTNET := $(shell cd ../../ && bash init-tools.sh | tail -1) SYSROOT := $(shell xcrun --sdk iphoneos --show-sdk-path) +BCL_LIBS = \ + System.Runtime.dll \ + System.Runtime.Extensions.dll \ + System.Collections.dll \ + System.Core.dll \ + System.Threading.dll \ + System.Threading.Tasks.dll \ + System.Linq.dll \ + System.Memory.dll \ + System.Runtime.InteropServices.dll \ + System.Text.Encoding.Extensions.dll \ + Microsoft.Win32.Primitives.dll \ + System.Console.dll + # once a new library is added here it should also be # added in mono_ios_register_modules() (runtime.m) all: prepare make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_MONO)/System.Private.CoreLib.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Runtime.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Runtime.Extensions.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Collections.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Core.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Threading.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Threading.Tasks.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Linq.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Memory.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Runtime.InteropServices.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Text.Encoding.Extensions.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/Microsoft.Win32.Primitives.dll - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/System.Console.dll + for lib in $(BCL_LIBS); do make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/$$lib; done make Program.dll.o # recompile Program.cs AOT @@ -34,15 +37,7 @@ Program.dll.o: bin/Program.dll Makefile # we need to copy some BCL libs to ARTIFACTS_MONO # to be able to aot other bcl libs prepare: - cp $(ARTIFACTS_BCL)/System.Memory.dll $(ARTIFACTS_MONO) - cp $(ARTIFACTS_BCL)/System.Collections.dll $(ARTIFACTS_MONO) - cp $(ARTIFACTS_BCL)/System.Threading.dll $(ARTIFACTS_MONO) - cp $(ARTIFACTS_BCL)/System.Threading.Thread.dll $(ARTIFACTS_MONO) - cp $(ARTIFACTS_BCL)/System.Runtime.dll $(ARTIFACTS_MONO) - cp $(ARTIFACTS_BCL)/System.Runtime.InteropServices.dll $(ARTIFACTS_MONO) - cp $(ARTIFACTS_BCL)/System.Text.Encoding.Extensions.dll $(ARTIFACTS_MONO) - cp $(ARTIFACTS_BCL)/Microsoft.Win32.Primitives.dll $(ARTIFACTS_MONO) - cp $(ARTIFACTS_BCL)/System.Console.dll $(ARTIFACTS_MONO) + for lib in $(BCL_LIBS); do cp $(ARTIFACTS_BCL)/$$lib $(ARTIFACTS_MONO); done bin/Program.dll: Program.cs $(DOTNET) build -c Debug Program.csproj diff --git a/src/mono/netcore/sample/iOS/Program.cs b/src/mono/netcore/sample/iOS/Program.cs index 6e3571df6f1d0..c1f99af192632 100644 --- a/src/mono/netcore/sample/iOS/Program.cs +++ b/src/mono/netcore/sample/iOS/Program.cs @@ -25,7 +25,7 @@ public static class Program // Called by native code, see main.m [MonoPInvokeCallback(typeof(Action))] - private static async void OnButtonClick() + private static void OnButtonClick() { ios_set_text("OnButtonClick! #" + counter++); } @@ -44,7 +44,6 @@ public static async Task Main(string[] args) await Task.Delay(100); } - // TODO: https://github.com/dotnet/runtime/issues/33667 Console.WriteLine("Done!"); } } \ No newline at end of file diff --git a/src/mono/netcore/sample/iOS/runtime.m b/src/mono/netcore/sample/iOS/runtime.m index a83f7589ad659..05f4dd2c488c9 100644 --- a/src/mono/netcore/sample/iOS/runtime.m +++ b/src/mono/netcore/sample/iOS/runtime.m @@ -247,6 +247,10 @@ void mono_ios_setup_execution_mode (void) { // for now, only Invariant Mode is supported (FIXME: integrate ICU) setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", TRUE); + // uncomment for debug output: + // + // setenv ("MONO_LOG_LEVEL", "debug", TRUE); + // setenv ("MONO_LOG_MASK", "all", TRUE); stdout_log = os_log_create ("net.dot.mono", "stdout"); @@ -292,4 +296,3 @@ void mono_ios_setup_execution_mode (void) // Print this so apps parsing logs can detect when we exited os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", res); } -