diff options
author | Alex Ghiondea <ghiondea.alexandru@microsoft.com> | 2015-12-02 00:46:33 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2015-12-02 01:13:17 +0300 |
commit | 9287f362cd75512a92d735630c363ccc44120677 (patch) | |
tree | bf8c85cb86b510770a0a334c62954547702833ef | |
parent | 1c0405707ef848c1a485ef0fa63452e4e12305ed (diff) |
Port System.Private.DeveloperExperience.Console to CoreRT
[tfs-changeset: 1553090]
16 files changed, 334 insertions, 8 deletions
diff --git a/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.Environment.cs b/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.Environment.cs index 040d1ba90..b429c01c1 100644 --- a/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.Environment.cs +++ b/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.Environment.cs @@ -7,14 +7,9 @@ using System.Runtime.InteropServices; internal static partial class Interop { - private static class Libraries - { - internal const string SystemPrivateCoreLibNative = "System.Private.CoreLib.Native"; - } - internal unsafe partial class Sys { - [DllImport(Libraries.SystemPrivateCoreLibNative)] + [DllImport(Interop.Libraries.SystemPrivateCoreLibNative)] internal static unsafe extern int GetEnvironmentVariable(byte* name, out IntPtr result); } } diff --git a/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.Libraries.cs b/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.Libraries.cs new file mode 100644 index 000000000..0737bd1df --- /dev/null +++ b/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.Libraries.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +internal static partial class Interop +{ + internal static class Libraries + { + internal const string SystemPrivateCoreLibNative = "System.Private.CoreLib.Native"; + } +} diff --git a/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.Write.cs b/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.Write.cs new file mode 100644 index 000000000..cab0a2f3b --- /dev/null +++ b/src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.Write.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Sys + { + /// <summary> + /// Writes the specified buffer to the provided open file descriptor + /// </summary> + /// <param name="fd">The file descriptor to try and write to</param> + /// <param name="buffer">The data to attempt to write</param> + /// <param name="bufferSize">The amount of data to write, in bytes</param> + /// <returns> + /// Returns the number of bytes written on success; otherwise, returns -1 and sets errno + /// </returns> + [DllImport(Interop.Libraries.SystemPrivateCoreLibNative, SetLastError = true)] + internal static unsafe extern int Write2(int fd, byte* buffer, int bufferSize); + } +} diff --git a/src/Common/src/Interop/Unix/libc/Interop.FileDescriptors.cs b/src/Common/src/Interop/Unix/libc/Interop.FileDescriptors.cs new file mode 100644 index 000000000..4eeec2ddb --- /dev/null +++ b/src/Common/src/Interop/Unix/libc/Interop.FileDescriptors.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +internal static partial class Interop +{ + internal static partial class Sys + { + internal static class FileDescriptors + { + internal const int STDIN_FILENO = 0; + internal const int STDOUT_FILENO = 1; + internal const int STDERR_FILENO = 2; + } + } +} diff --git a/src/Common/src/Interop/Windows/mincore/Interop.Console.cs b/src/Common/src/Interop/Windows/mincore/Interop.Console.cs new file mode 100644 index 000000000..1e4526a90 --- /dev/null +++ b/src/Common/src/Interop/Windows/mincore/Interop.Console.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + private static class Libraries + { + internal const string Process = "api-ms-win-core-processenvironment-l1-1-0.dll"; + internal const string Console = "api-ms-win-core-console-l1-1-0.dll"; + } + + internal static unsafe partial class mincore + { + [DllImport("Libraries.Process")] + internal static extern IntPtr GetStdHandle(int nStdHandle); + + [DllImport("Libraries.Console", EntryPoint = "WriteConsoleW")] + internal static unsafe extern bool WriteConsole(IntPtr hConsoleOutput, byte* lpBuffer, int nNumberOfCharsToWrite, out int lpNumberOfCharsWritten, IntPtr lpReservedMustBeNull); + } +} diff --git a/src/Common/src/Interop/Windows/mincore/Interop.HandleTypes.cs b/src/Common/src/Interop/Windows/mincore/Interop.HandleTypes.cs new file mode 100644 index 000000000..4076d0e3e --- /dev/null +++ b/src/Common/src/Interop/Windows/mincore/Interop.HandleTypes.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +internal partial class Interop +{ + internal partial class mincore + { + internal partial class HandleTypes + { + internal const int INVALID_HANDLE_VALUE = -1; + internal const int STD_ERROR_HANDLE = -12; + } + } +} diff --git a/src/Native/Common/pal_utilities.h b/src/Native/Common/pal_utilities.h new file mode 100644 index 000000000..e78f68d73 --- /dev/null +++ b/src/Native/Common/pal_utilities.h @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#pragma once + +#include <assert.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <type_traits> + +/** +* Cast a positive value typed as a signed integer to the +* appropriately sized unsigned integer type. +* +* We use this when we've already ensured that the value is positive, +* but we don't want to cast to a specific unsigned type as that could +* inadvertently defeat the compiler's narrowing conversion warnings +* (which we treat as error). +*/ +template <typename T> +inline typename std::make_unsigned<T>::type UnsignedCast(T value) +{ + assert(value >= 0); + return static_cast<typename std::make_unsigned<T>::type>(value); +} + diff --git a/src/Native/System.Private.CoreLib.Native/CMakeLists.txt b/src/Native/System.Private.CoreLib.Native/CMakeLists.txt index b76b3964a..cfd25e889 100644 --- a/src/Native/System.Private.CoreLib.Native/CMakeLists.txt +++ b/src/Native/System.Private.CoreLib.Native/CMakeLists.txt @@ -3,6 +3,7 @@ project(System.Private.CoreLib.Native) set(NATIVE_SOURCES pal_environment.cpp pal_memory.cpp + pal_io.cpp ) add_library(System.Private.CoreLib.Native diff --git a/src/Native/System.Private.CoreLib.Native/pal_io.cpp b/src/Native/System.Private.CoreLib.Native/pal_io.cpp new file mode 100644 index 000000000..04fed95e1 --- /dev/null +++ b/src/Native/System.Private.CoreLib.Native/pal_io.cpp @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <assert.h> +#include <errno.h> +#include "pal_utilities.h" + +extern "C" int32_t Write2(int32_t fd, const void* buffer, int32_t bufferSize) +{ + assert(buffer != nullptr || bufferSize == 0); + assert(bufferSize >= 0); + + if (bufferSize < 0) + { + errno = ERANGE; + return -1; + } + + ssize_t count = write(fd, buffer, UnsignedCast(bufferSize)); + assert(count >= -1 && count <= bufferSize); + return static_cast<int32_t>(count); +} + diff --git a/src/Native/configure.cmake b/src/Native/configure.cmake index 81fc4eecc..bb3189571 100644 --- a/src/Native/configure.cmake +++ b/src/Native/configure.cmake @@ -3,6 +3,8 @@ include(CheckStructHasMember) include(CheckCXXSourceCompiles) include(CheckCXXSourceRuns) +add_compile_options(-I${CMAKE_CURRENT_SOURCE_DIR}/Common) + if (NOT WIN32) include_directories(SYSTEM /usr/local/include) endif () diff --git a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 64a2f5d87..02370513c 100644 --- a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -480,7 +480,7 @@ </ItemGroup> <!-- Windows is default build --> - <ItemGroup Condition="'$(OSGroup)' == 'Windows_NT'"> + <ItemGroup Condition="'$(TargetsWindows)'=='true'"> <Compile Include="System\Globalization\CultureInfo.Win32.cs" /> <Compile Include="System\Globalization\CompareInfo.Win32.cs" /> <Compile Include="System\Globalization\CultureData.Win32.cs" /> @@ -492,7 +492,7 @@ <Compile Include="..\..\Common\src\Interop\Windows\mincore\Interop.Environment.cs" /> </ItemGroup> - <ItemGroup Condition="'$(OSGroup)' != 'Windows_NT'"> + <ItemGroup Condition="'$(TargetsUnix)'=='true'"> <Compile Include="System\Globalization\CultureInfo.Dummy.cs" /> <Compile Include="System\Globalization\CompareInfo.Dummy.cs" /> <Compile Include="System\Globalization\CultureData.Dummy.cs" /> @@ -500,6 +500,7 @@ <Compile Include="System\Globalization\CalendarData.Dummy.cs" /> <Compile Include="System\Environment.EnvironmentVariables.Unix.cs" /> <Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.Environment.cs" /> + <Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.Libraries.cs" /> <Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.StringHelper.cs" /> </ItemGroup> diff --git a/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/ConsolePal.Unix.cs b/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/ConsolePal.Unix.cs new file mode 100644 index 000000000..2be4652d6 --- /dev/null +++ b/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/ConsolePal.Unix.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Internal.DeveloperExperience +{ + internal static class ConsolePal + { + internal unsafe static void WriteError(string errorMessage) + { + byte[] errorMessageAsBytes = Interop.StringHelper.GetBytesFromUTF8string(errorMessage); + fixed (byte* pBuffer = errorMessageAsBytes) + { + Interop.Sys.Write2(Interop.Sys.FileDescriptors.STDERR_FILENO, pBuffer, errorMessageAsBytes.Length); + } + + // Write new line + byte newLine = (byte) '\n'; + Interop.Sys.Write2(Interop.Sys.FileDescriptors.STDERR_FILENO, &newLine, 1); + + } + } +}
\ No newline at end of file diff --git a/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/ConsolePal.Windows.cs b/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/ConsolePal.Windows.cs new file mode 100644 index 000000000..f9ed5eacb --- /dev/null +++ b/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/ConsolePal.Windows.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Internal.DeveloperExperience +{ + internal static class ConsolePal + { + private static IntPtr s_consoleErrorHandle = Interop.mincore.GetStdHandle(Interop.mincore.HandleTypes.STD_ERROR_HANDLE); + + internal unsafe static void WriteError(string errorMessage) + { + if (s_consoleErrorHandle == new IntPtr(Interop.mincore.HandleTypes.INVALID_HANDLE_VALUE)) + { + // ensure we have a valid handle before writing to it + return; + } + + fixed (char *pBuffer = errorMessage) + { + int numberOfCharsWritten; + Interop.mincore.WriteConsole(s_consoleErrorHandle, (byte*)pBuffer, errorMessage.Length, out numberOfCharsWritten, IntPtr.Zero); + } + + // Write new line + fixed (char* pBuffer = "\r\n") + { + int numberOfCharsWritten; + Interop.mincore.WriteConsole(s_consoleErrorHandle, (byte*)pBuffer, 2, out numberOfCharsWritten, IntPtr.Zero); + } + } + } +}
\ No newline at end of file diff --git a/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/DeveloperExperienceConnector.cs b/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/DeveloperExperienceConnector.cs new file mode 100644 index 000000000..c1aa19135 --- /dev/null +++ b/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/DeveloperExperienceConnector.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; + +namespace Internal.DeveloperExperience +{ + public static class DeveloperExperienceConnectorConsole + { + // This method is targeted by the MainMethodInjector transform. This method exists in various DeveloperExperience.*.dll's. + // The MainMethodInjector chooses an appropriate one (or none) depending on the build configuration and app structure. + // + // The Console DeveloperExperience is chosen if the main exe has a reference to System.Console. This is for internal Microsoft use only. + // It should remain small enough that we don't bother shutting it off on retail builds. + public static void Initialize() + { + DeveloperExperience.Default = new DeveloperExperienceConsole(); + return; + } + } +} + + diff --git a/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/DeveloperExperienceConsole.cs b/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/DeveloperExperienceConsole.cs new file mode 100644 index 000000000..17121740b --- /dev/null +++ b/src/System.Private.DeveloperExperience.Console/src/Internal/DeveloperExperience/DeveloperExperienceConsole.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; +using global::Internal.StackTraceGenerator; + +namespace Internal.DeveloperExperience +{ + internal sealed class DeveloperExperienceConsole : DeveloperExperience + { + public sealed override void WriteLine(String s) + { + ConsolePal.WriteError(s); + } + + public sealed override String CreateStackTraceString(IntPtr ip, bool includeFileInfo) + { + String s = Internal.StackTraceGenerator.StackTraceGenerator.CreateStackTraceString(ip, includeFileInfo); + if (s != null) + return s; + return base.CreateStackTraceString(ip, includeFileInfo); + } + + public sealed override void TryGetSourceLineInfo(IntPtr ip, out string fileName, out int lineNumber, out int columnNumber) + { + Internal.StackTraceGenerator.StackTraceGenerator.TryGetSourceLineInfo(ip, out fileName, out lineNumber, out columnNumber); + // we take whatever data StackTraceGenerator can get (none/partial/all). No reason to fall-back because the base-type + // never finds anything. + } + } +} + diff --git a/src/System.Private.DeveloperExperience.Console/src/System.Private.DeveloperExperience.Console.csproj b/src/System.Private.DeveloperExperience.Console/src/System.Private.DeveloperExperience.Console.csproj new file mode 100644 index 000000000..3518511d0 --- /dev/null +++ b/src/System.Private.DeveloperExperience.Console/src/System.Private.DeveloperExperience.Console.csproj @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <AssemblyName>System.Private.DeveloperExperience.Console</AssemblyName> + <OutputType>Library</OutputType> + <ProjectGuid>{F9EF39E7-C8E4-4776-A952-FEF7A1FC2D3B}</ProjectGuid> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <TargetPlatformIdentifier>Portable</TargetPlatformIdentifier> + <TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier> + <TargetFrameworkProfile>Profile7</TargetFrameworkProfile> + <TargetFrameworkMonikerDisplayName>.NET Portable Subset</TargetFrameworkMonikerDisplayName> + <ImplicitlyExpandTargetFramework>false</ImplicitlyExpandTargetFramework> + </PropertyGroup> + + <!-- Default configurations to help VS understand the options --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <PlatformTarget>x86</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <PlatformTarget>x86</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|amd64' "> + <PlatformTarget>x64</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|amd64' "> + <PlatformTarget>x64</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|arm' "> + <PlatformTarget>arm</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|arm' "> + <PlatformTarget>arm</PlatformTarget> + </PropertyGroup> + <ItemGroup> + <Compile Include="Internal\DeveloperExperience\DeveloperExperienceConnector.cs" /> + <Compile Include="Internal\DeveloperExperience\DeveloperExperienceConsole.cs" /> + </ItemGroup> + + <ItemGroup Condition="'$(TargetsWindows)'=='true'"> + <Compile Include="..\..\Common\src\Interop\Windows\mincore\Interop.Console.cs" /> + <Compile Include="..\..\Common\src\Interop\Windows\mincore\Interop.HandleTypes.cs" /> + <Compile Include="Internal\DeveloperExperience\ConsolePal.Windows.cs" /> + </ItemGroup> + + <ItemGroup Condition="'$(TargetsUnix)'=='true'"> + <Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.StringHelper.cs" /> + <Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.Libraries.cs" /> + <Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.Write.cs" /> + <Compile Include="..\..\Common\src\Interop\Unix\libc\Interop.FileDescriptors.cs" /> + <Compile Include="Internal\DeveloperExperience\ConsolePal.Unix.cs" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\..\System.Private.CoreLib\src\System.Private.CoreLib.csproj" /> + <ProjectReference Include="..\..\AotPackageReference\AotPackageReference.depproj"> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + + <ReferencePath Include="$(AotPackageReferencePath)\System.Runtime.dll" /> + <ReferencePath Include="$(AotPackageReferencePath)\System.Runtime.Extensions.dll" /> + <ReferencePath Include="$(AotPackageReferencePath)\System.Diagnostics.Tracing.dll" /> + <ReferencePath Include="$(AotPackageReferencePath)\System.Collections.dll" /> + <ReferencePath Include="$(AotPackageReferencePath)\System.Resources.ResourceManager.dll" /> + + <ProjectReference Include="..\..\System.Private.StackTraceGenerator\src\System.Private.StackTraceGenerator.csproj" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> |