.NET探索平臺條件編譯

HueiFeng發表於2021-01-17

前言

今天偶然機會,翻了一下大學期間的書籍《C程式設計》,好吧,當我翻著翻著,翻到了符號常量(#define指令)中,是啊,這是一個前處理器指令,記得在Magicodes.IE中針對平臺選擇不同的庫,哈哈,這是一個典型的根據平臺進行條件處理,好吧,根據這些內容,讓我感覺在今天,我需要對#define指令以及在.NET中的平臺條件處理,以及平臺的條件編譯進行記錄一下。

file

define

我們可通過define來定義符號,然後將符號用在#if指令表示式中,如下所示:

#define PI

通過上面這些內容可能很難去了解這該如何使用,其實#define在我們的編碼過程中也是很少去使用的,我們繼續往下看。

其實對於前處理器,在我們除錯以及執行時的作用是比較大的,比如說對某些程式碼限制編譯,另一方變其實還可以對程式碼進行環境或者版本的控制,這些都是Ok的,最後我們結合著控制語句#if來看一下:

#define PI
using System;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            #if (PI)
            Console.WriteLine("PI is defined");
            #else
            Console.WriteLine("PI is not defined");
            #endif
            Console.ReadKey();
        }
    }
}

當我們的頭部宣告#define PI時,我們也可以看到編譯的感知功能可以為我們將控制語句進行切換,是啊,我們可以在頭部進行宣告。

條件編譯符號

對於上面我們可以直接通過#define去進行條件編譯,而對於在.cs檔案中我們去定義它達到的只是區域性的使用,我們如果說想全域性的控制,全域性的應用該如何操作?其實我們是可以通過DefineConstants屬性進行操作。

file

我們可以開啟專案檔案進行檢視,屬性如下所示:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5</TargetFramework>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DefineConstants>TRACE;PI</DefineConstants>
  </PropertyGroup>
</Project>

當然了,我們一方面是可通過VS對專案的屬性進行編輯,而另一方面,我們是可通過直接對專案檔案進行修改編輯操作.這樣其實達到了一個可控制性.

RuntimeInformation

對於程式碼中也是可以進行平臺的邏輯判斷的,在.NET Core 1.0的時候其實已經新增了System.Runtime.InteropServices.RuntimeInformation對於這個類的新增,使我們可以動態的去判斷當前的作業系統(OS),以及我們可通過這些動態判斷為我們的業務邏輯進行不同的處理行為。

判斷當前作業系統如下所示:

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
    Console.WriteLine("Running on Linux!");
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
    Console.WriteLine("Running on macOS!");
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    Console.WriteLine("Running on Windows!");

MSBuild & RuntimeInformation

對於條件編譯,之前我們已經手動的操作過一次了,是我們可以根據不同的環境值進行對程式碼編譯內容的控制,如果說我想根據當前的作業系統(OS)動態的進行條件編譯,該如何進行操作。

其實我們在專案檔案中進行呼叫System.Runtime.InteropServices.RuntimeInformation進行我們的條件處理。下面我們看一下在MSBuild中如何呼叫System.Runtime.InteropServices.RuntimeInformation如下所示:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5</TargetFramework>
    <IsWindows Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">true</IsWindows>
    <IsOSX Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">true</IsOSX>
    <IsLinux Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">true</IsLinux>
  </PropertyGroup>

  <Target Name="PrintRID" BeforeTargets="Build">
    <Message Text="IsWindows $(IsWindows)" Importance="high" />
    <Message Text="IsOSX $(IsOSX)" Importance="high" />
    <Message Text="IsLinux $(IsLinux)" Importance="high" />
  </Target>

</Project>

我們是可以通過visual studio或者說通過CLI直接執行構建命令dotnet build,我們在Windows作業系統中測試一下,輸出結果如下所示:

C:\Users\hueif\source\repos\ConsoleApp2\ConsoleApp2>dotnet build
用於 .NET 的 Microsoft (R) 生成引擎版本 16.8.0+126527ff1
版權所有(C) Microsoft Corporation。保留所有權利。

  正在確定要還原的專案…
  所有專案均是最新的,無法還原。
  你正在使用 .NET 的預覽版。請檢視 https://aka.ms/dotnet-core-preview
  ConsoleApp2 -> C:\Users\hueif\source\repos\ConsoleApp2\ConsoleApp2\bin\Debug\net5\ConsoleApp2.dll
  IsWindows true
  IsOSX
  IsLinux

可以看出,在IsWindows中對應著true,說明我們的操作生效了,那麼我們繼續修改我們的程式,看看如何使用條件編譯,去控制我們的程式碼,我們在專案檔案中新增如下片段:

  <PropertyGroup Condition="'$(IsWindows)'=='true'">
    <DefineConstants>Windows</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition="'$(IsOSX)'=='true'">
    <DefineConstants>OSX</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition="'$(IsLinux)'=='true'">
    <DefineConstants>Linux</DefineConstants>
  </PropertyGroup>

通過如上語句,我們可以對DefineConstants屬性進行條件判斷,條件性處理,同樣我們在程式碼中也是通過該值進行判斷,如下所示:

        static void Main(string[] args)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                Console.WriteLine("Running on Linux!");
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                Console.WriteLine("Running on macOS!");
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                Console.WriteLine("Running on Windows!");

            #if Linux
                    Console.WriteLine("Build on Linux!"); 
            #elif OSX
                    Console.WriteLine("Build on macOS!"); 
            #elif Windows
            Console.WriteLine("Build in Windows!");
            #endif
            Console.ReadKey();
        }

下面我們來驗證一下結果,是否跟我們想象中的一樣

Running on Windows!
Build in Windows!

結果沒問題,已達到預期的效果。

References

https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/preprocessor-directives/preprocessor-define

https://blog.walterlv.com/post/how-to-define-preprocessor-symbols.html

相關文章