Skip to content

Commit

Permalink
Adding crosstargeting in order to be able to call WinRT APIs in net5.0 (
Browse files Browse the repository at this point in the history
#1217)

* Adding crosstargeting in order to be able to call WinRT APIs in net5.0

* Only build Windows-specific build when running on Windows SDK

* Addressing PR Feedback

* Removing accidental push changing TFMs

* Removing blank spaces on Error message
  • Loading branch information
joperezr authored Oct 20, 2020
1 parent 526af54 commit f5b974b
Show file tree
Hide file tree
Showing 16 changed files with 298 additions and 49 deletions.
2 changes: 1 addition & 1 deletion eng/Compilers.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<!-- This is set to false by default when using the compilers' NuGet package. -->
<UseSharedCompilation>true</UseSharedCompilation>

<CompilerVersion>3.6.0-2.20166.2</CompilerVersion>
<CompilerVersion>3.8.0-4.final</CompilerVersion>
</PropertyGroup>

<PropertyGroup>
Expand Down
4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"tools": {
"dotnet": "5.0.100-rc.1.20452.10",
"dotnet": "5.0.100-rc.2.20479.15",
"runtimes": {
"dotnet/x64": [
"2.1.11"
]
}
},
"sdk": {
"version": "5.0.100-rc.1.20452.10"
"version": "5.0.100-rc.2.20479.15"
},
"msbuild-sdks": {
"Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20506.7",
Expand Down
2 changes: 1 addition & 1 deletion src/System.Device.Gpio/Interop/Unix/Interop.Libraries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

internal partial class Interop
internal static partial class Interop
{
private const string LibcLibrary = "libc";
}
34 changes: 30 additions & 4 deletions src/System.Device.Gpio/System.Device.Gpio.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFrameworks>netstandard2.0;net5.0</TargetFrameworks>
<TargetFrameworks Condition="$(NETCoreSdkRuntimeIdentifier.StartsWith('win'))">$(TargetFrameworks);net5.0-windows10.0.17763.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>preview</LangVersion>
<IsPackable>true</IsPackable>
Expand All @@ -10,17 +11,19 @@
<Compile Remove="winmd\**" />
<EmbeddedResource Remove="winmd\**" />
<None Remove="winmd\**" />
<None Include="buildTransitive\net5.0\System.Device.Gpio.targets" Pack="true" PackagePath="\buildTransitive\net5.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="$(MicrosoftWin32RegistryPackageVersion)" /> <!-- This is Windows specific -->
<PackageReference Include="System.Runtime.WindowsRuntime" Version="$(SystemRuntimeWindowsRuntimePackageVersion)" /> <!-- This is Windows specific -->
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.3" />
<PackageReference Include="System.Memory" Version="4.5.3" />
<PackageReference Include="System.Runtime.InteropServices.WindowsRuntime" Version="4.3.0" /> <!-- This is Windows specific -->
<PackageReference Include="Microsoft.DotNet.GenAPI" Version="$(MicrosoftDotNetGenApiPackageVersion)">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Runtime.WindowsRuntime" Version="$(SystemRuntimeWindowsRuntimePackageVersion)" />
<PackageReference Include="System.Runtime.InteropServices.WindowsRuntime" Version="4.3.0" />

<Reference Include="Windows.Devices.DevicesLowLevelContract">
<HintPath>winmd\Windows.Devices.DevicesLowLevelContract.winmd</HintPath>
<IsWinMDFile>true</IsWinMDFile>
Expand All @@ -35,4 +38,27 @@
</Reference>
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' != 'net5.0'">
<!--Remove the Linux-specific code-->
<Compile Remove="System\Device\Gpio\Drivers\Windows10Driver.notSupported.cs" />
<Compile Remove="System\Device\I2c\I2cDevice.nonWindows.cs" />
<Compile Remove="System\Device\Pwm\PwmChannel.nonWindows.cs" />
<Compile Remove="System\Device\Spi\SpiDevice.nonWindows.cs" />
<Compile Remove="System\Device\CommonHelpers.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
<!--Remove Windows Code-->
<Compile Remove="Interop\Windows\WinRT\*.cs" />
<Compile Remove="System\Device\Gpio\Drivers\Windows10DriverPin.cs" />
<Compile Remove="System\Device\Gpio\Drivers\Windows10Driver.cs" />
<Compile Remove="System\Device\I2c\Devices\Windows10I2cDevice.cs" />
<Compile Remove="System\Device\Pwm\Channels\Windows10PwmChannel.cs" />
<Compile Remove="System\Device\Spi\Devices\Windows10SpiDevice.cs" />
<Compile Remove="System\Device\I2c\I2cDevice.Windows.cs" />
<Compile Remove="System\Device\Pwm\PwmChannel.Windows.cs" />
<Compile Remove="System\Device\Spi\SpiDevice.Windows.cs" />

</ItemGroup>

</Project>
14 changes: 14 additions & 0 deletions src/System.Device.Gpio/System/Device/CommonHelpers.cs
Original file line number Diff line number Diff line change
@@ -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.

namespace System.Device
{
internal static class CommonHelpers
{
private const string WindowsPlatformTargetingFormat = "In order to use {0} on Windows with .NET 5.0 it is required for your application to target net5.0-windows10.0.17763.0 or higher. Please add that to your target frameworks in your project file.";

public static string GetFormattedWindowsPlatformTargetingErrorMessage(string className)
=> string.Format(WindowsPlatformTargetingFormat, className);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// 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.Threading;

namespace System.Device.Gpio.Drivers
{
/// <summary>
/// A GPIO driver for Windows 10 IoT.
/// </summary>
public class Windows10Driver : GpioDriver
{
/// <summary>
/// Initializes a new instance of the <see cref="Windows10Driver"/> class.
/// </summary>
public Windows10Driver()
{
// If we land in this method it means the console application is running on Windows and targetting net5.0 (without specifying Windows platform)
// In order to call WinRT code in net5.0 it is required for the application to target the specific platform
// so we throw the bellow exception with a detailed message in order to instruct the consumer on how to move forward.
throw new PlatformNotSupportedException(CommonHelpers.GetFormattedWindowsPlatformTargetingErrorMessage(nameof(Windows10Driver)));
}

/// <inheritdoc />
protected internal override int PinCount => throw new PlatformNotSupportedException();

/// <inheritdoc />
protected internal override void AddCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback)
{
throw new PlatformNotSupportedException();
}

/// <inheritdoc />
protected internal override void ClosePin(int pinNumber)
{
throw new PlatformNotSupportedException();
}

/// <inheritdoc />
protected internal override int ConvertPinNumberToLogicalNumberingScheme(int pinNumber)
{
throw new PlatformNotSupportedException();
}

/// <inheritdoc />
protected internal override PinMode GetPinMode(int pinNumber)
{
throw new PlatformNotSupportedException();
}

/// <inheritdoc />
protected internal override bool IsPinModeSupported(int pinNumber, PinMode mode)
{
throw new PlatformNotSupportedException();
}

/// <inheritdoc />
protected internal override void OpenPin(int pinNumber)
{
throw new PlatformNotSupportedException();
}

/// <inheritdoc />
protected internal override PinValue Read(int pinNumber)
{
throw new PlatformNotSupportedException();
}

/// <inheritdoc />
protected internal override void RemoveCallbackForPinValueChangedEvent(int pinNumber, PinChangeEventHandler callback)
{
throw new PlatformNotSupportedException();
}

/// <inheritdoc />
protected internal override void SetPinMode(int pinNumber, PinMode mode)
{
throw new PlatformNotSupportedException();
}

/// <inheritdoc />
protected internal override WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, CancellationToken cancellationToken)
{
throw new PlatformNotSupportedException();
}

/// <inheritdoc />
protected internal override void Write(int pinNumber, PinValue value)
{
throw new PlatformNotSupportedException();
}
}
}
24 changes: 24 additions & 0 deletions src/System.Device.Gpio/System/Device/I2c/I2cDevice.Windows.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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.Runtime.CompilerServices;

namespace System.Device.I2c
{
/// <summary>
/// The communications channel to a device on an I2C bus.
/// </summary>
public abstract partial class I2cDevice
{
[MethodImpl(MethodImplOptions.NoInlining)]
private static I2cDevice CreateWindows10I2cDevice(I2cConnectionSettings settings)
{
// This wrapper is needed to prevent Mono from loading Windows10I2cDevice
// which causes all fields to be loaded - one of such fields is WinRT type which does not
// exist on Linux which causes TypeLoadException.
// Using NoInlining and no explicit type prevents this from happening.
return new Windows10I2cDevice(settings);
}
}
}
14 changes: 1 addition & 13 deletions src/System.Device.Gpio/System/Device/I2c/I2cDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
// 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.Runtime.CompilerServices;

namespace System.Device.I2c
{
/// <summary>
/// The communications channel to a device on an I2C bus.
/// </summary>
public abstract class I2cDevice : IDisposable
public abstract partial class I2cDevice : IDisposable
{
/// <summary>
/// The connection settings of a device on an I2C bus. The connection settings are immutable after the device is created
Expand Down Expand Up @@ -77,16 +75,6 @@ public static I2cDevice Create(I2cConnectionSettings settings)
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static I2cDevice CreateWindows10I2cDevice(I2cConnectionSettings settings)
{
// This wrapper is needed to prevent Mono from loading Windows10I2cDevice
// which causes all fields to be loaded - one of such fields is WinRT type which does not
// exist on Linux which causes TypeLoadException.
// Using NoInlining and no explicit type prevents this from happening.
return new Windows10I2cDevice(settings);
}

/// <inheritdoc cref="IDisposable.Dispose"/>
public void Dispose()
{
Expand Down
23 changes: 23 additions & 0 deletions src/System.Device.Gpio/System/Device/I2c/I2cDevice.nonWindows.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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.Runtime.CompilerServices;

namespace System.Device.I2c
{
/// <summary>
/// The communications channel to a device on an I2C bus.
/// </summary>
public abstract partial class I2cDevice
{
[MethodImpl(MethodImplOptions.NoInlining)]
private static I2cDevice CreateWindows10I2cDevice(I2cConnectionSettings settings)
{
// If we land in this method it means the console application is running on Windows and targetting net5.0 (without specifying Windows platform)
// In order to call WinRT code in net5.0 it is required for the application to target the specific platform
// so we throw the bellow exception with a detailed message in order to instruct the consumer on how to move forward.
throw new PlatformNotSupportedException(CommonHelpers.GetFormattedWindowsPlatformTargetingErrorMessage(nameof(I2cDevice)));
}
}
}
28 changes: 28 additions & 0 deletions src/System.Device.Gpio/System/Device/Pwm/PwmChannel.Windows.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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.Runtime.CompilerServices;

namespace System.Device.Pwm
{
/// <summary>
/// Represents a single PWM channel.
/// </summary>
public abstract partial class PwmChannel
{
[MethodImpl(MethodImplOptions.NoInlining)]
private static PwmChannel CreateWindows10PwmChannel(int chip, int channel, int frequency, double dutyCyclePercentage)
{
// This wrapper is needed to prevent Mono from loading Windows10PwmChannel
// which causes all fields to be loaded - one of such fields is WinRT type which does not
// exist on Linux which causes TypeLoadException.
// Using NoInlining and no explicit type prevents this from happening.
return new Channels.Windows10PwmChannel(
chip,
channel,
frequency,
dutyCyclePercentage);
}
}
}
16 changes: 0 additions & 16 deletions src/System.Device.Gpio/System/Device/Pwm/PwmChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// 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.Runtime.CompilerServices;

namespace System.Device.Pwm
{
/// <summary>
Expand Down Expand Up @@ -103,19 +101,5 @@ private static bool IsBeagleBoneKernel()
return false;
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static PwmChannel CreateWindows10PwmChannel(int chip, int channel, int frequency, double dutyCyclePercentage)
{
// This wrapper is needed to prevent Mono from loading Windows10PwmChannel
// which causes all fields to be loaded - one of such fields is WinRT type which does not
// exist on Linux which causes TypeLoadException.
// Using NoInlining and no explicit type prevents this from happening.
return new Channels.Windows10PwmChannel(
chip,
channel,
frequency,
dutyCyclePercentage);
}
}
}
23 changes: 23 additions & 0 deletions src/System.Device.Gpio/System/Device/Pwm/PwmChannel.nonWindows.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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.Runtime.CompilerServices;

namespace System.Device.Pwm
{
/// <summary>
/// Represents a single PWM channel.
/// </summary>
public abstract partial class PwmChannel
{
[MethodImpl(MethodImplOptions.NoInlining)]
private static PwmChannel CreateWindows10PwmChannel(int chip, int channel, int frequency, double dutyCyclePercentage)
{
// If we land in this method it means the console application is running on Windows and targetting net5.0 (without specifying Windows platform)
// In order to call WinRT code in net5.0 it is required for the application to target the specific platform
// so we throw the bellow exception with a detailed message in order to instruct the consumer on how to move forward.
throw new PlatformNotSupportedException(CommonHelpers.GetFormattedWindowsPlatformTargetingErrorMessage(nameof(PwmChannel)));
}
}
}
24 changes: 24 additions & 0 deletions src/System.Device.Gpio/System/Device/Spi/SpiDevice.Windows.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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.Runtime.CompilerServices;

namespace System.Device.Spi
{
/// <summary>
/// The communications channel to a device on a SPI bus.
/// </summary>
public abstract partial class SpiDevice
{
[MethodImpl(MethodImplOptions.NoInlining)]
private static SpiDevice CreateWindows10SpiDevice(SpiConnectionSettings settings)
{
// This wrapper is needed to prevent Mono from loading Windows10SpiDevice
// which causes all fields to be loaded - one of such fields is WinRT type which does not
// exist on Linux which causes TypeLoadException.
// Using NoInlining and no explicit type prevents this from happening.
return new Windows10SpiDevice(settings);
}
}
}
Loading

0 comments on commit f5b974b

Please sign in to comment.