Can I define constants based on the runtime identifier in .NET Core?
Asked Answered
L

2

9

I have a .NET Core Console application. My goal here is to be able to conditionally DLLImport a function and call it, but only on Windows runtimes.

I thought maybe if I could access the runtime identifier in the csproj file, I could conditionally define a constant for that runtime, then in my c# I could surround the DLLImport and calls in #if/#endif blocks.

Is it possible to set compilation constants within a csproj based on the runtime the project is being built for? This is specifically for an SDK-style Project format (that starts with <Project Sdk="Microsoft.NET.Sdk">) that is targeting .NET Core.

Note: this question gets close, but is for project.json style projects.

Alternately, is there a better approach to accomplish my goal?

Landloper answered 4/5, 2018 at 1:52 Comment(1)
you can define compiler constants in .csproj depending on some conditions. For example: <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <DefineConstants>TRACE;DEBUG;ABC;NETCOREAPP2_0</DefineConstants> </PropertyGroup> This xml node is located directly in the root "Project"-node.Nikaniki
J
16

If you are building and publishing for different runtimes by passing different --runtime options (MSBuild property RuntimeIdentifier), you can condition on that property in the csproj file (allowing you to use #if BUILT_FOR_WINDOWS in your C# code):

<PropertyGroup>
  <DefineConstants Condition="'$(RuntimeIdentifier)' == 'win-x64'">$(DefineConstants);BUILT_FOR_WINDOWS</DefineConstants>
</PropertyGroup>

However you can also test the current OS at run time using:

using System.Runtime.InteropServices;
…

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
    // call windows function here
}
else
{
    // do something else here
}

As long as a function marked with [DllImport(…)] is not called on an OS where the library / method cannot be found, there shouldn't be any problems. Do note that DllImport() can also probe for different libraries depending on the os - so DllImport("foo") would check for foo.dll, foo.dylib, libfoo.so etc.

Jase answered 4/5, 2018 at 6:15 Comment(2)
When you copy this answer, make sure you don't need win10-x64 instead of win-x64. The latter refers to the portable dotnet runtime. See learn.microsoft.com/en-us/dotnet/core/rid-catalog#windows-ridsGoodly
perhaps you have a complete code example ? I can't make it work. There's no #if RID available. And if I define them it's not clear how to set a value there. In case of #if NET 6 and so on all is clear but it does not in case of RIDsSoandso
Y
3

Adding to a Martin Ullrich's answer: if you want to define constants based on RuntimeIdentifier in a referenced library project as opposed to a project with application entry point make sure that you include the list of identifiers which you use in a RuntimeIdentifiers property in the project's .csproj file, for example:

<PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <RuntimeIdentifiers>linux-x64;linux-arm</RuntimeIdentifiers>
</PropertyGroup>

If you don't do it then the constants will not be defined as RuntimeIdentifier property will not be passed to the csproj, as was in my case.

Source: https://github.com/dotnet/core/issues/2678#issuecomment-498967871

Yehudi answered 15/9, 2021 at 20:54 Comment(2)
When building (without publishing) a NET 6 cross-platform console app, there is no RuntimeIdentifier set. I can start and debug the application from VS 2022 choosing Windows or WSL/Ubuntu as target, but I did not find any possibility to define BUILT_FOR_WINDOWS or BUILT_FOR_LINUX to be used in the C# codeSettee
The following works with build and not publish: <DefineConstants Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier)' == 'win-x64'" >$(DefineConstants);BUILT_FOR_WINDOWS;BUILT_FOR_X64</DefineConstants>Tavey

© 2022 - 2024 — McMap. All rights reserved.