LoginSignup
1
0

More than 1 year has passed since last update.

.NET 6 + VB でも NativeAOT がしたい!

Last updated at Posted at 2021-12-12

はじめに

これは、Visual Basic Advent Calendar 2021の9日目の記事となります。

別のところで C#用のNativeAOTの記事を書きました。Qiitaでは2つのAdvent Calendarのリンクができません。

NativeAOTとは

ILを完全にネイティブコードに落とし込むオープンソースプロジェクトです。ILからの変換なので、C#以外にVisual BasicやF#でも可能です。
2021年以降は、NativeAOTリポジトリ
https://github.com/dotnet/runtimelab/tree/feature/NativeAOT
※将来的にはメインプロジェクトに統合される予定

NativeAOTの準備

C++ ビルドツール

マイクロソフト C++ ビルドツールのインストール
https://visualstudio.microsoft.com/ja/visual-cpp-build-tools/

C++ によるデスクトップ開発

Visual Studio Installerを起動します。変更ボタンをクリックします。
ワークロードタブに「C++によるデスクトップ開発」にチェックを入れ、「インストール」をクリックします。
image.png

ビルド

HelloWorldのサンプルが下記サイトにあります。
https://github.com/dotnet/runtimelab/tree/feature/NativeAOT/samples/HelloWorld

HelloWorldのままではつまらないので、今回はフィボナッチ数列にしてみます。

プロジェクト生成

NativeAOTは、ILからの変換なので、C#以外にVisual BasicやF#でも可能です。
今回は、Visual Basicを指定します。
自分はC:\WorkSpaceフォルダにいつもプロジェクトを生成しています。

> cd C:\WorkSpace
> dotnet new console -o FibonacciVB -lang VB
> cd FibonacciVB

プロジェクトにNativeAOTを追加

> dotnet new nugetconfig
テンプレート "NuGet Config" が正常に作成されました。

nuget.configファイルが追加されます。

nuget.configの編集

nuget.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <!--To inherit the global NuGet package sources remove the <clear/> line below -->
    <clear />
    <add key="nuget" value="https://api.nuget.org/v3/index.json" />
  </packageSources>
</configuration>

packageSources要素のより下を下記の置き換えます。

<add key="dotnet-experimental" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />

最終結果

nuget.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <!--To inherit the global NuGet package sources remove the <clear/> line below -->
    <clear />
    <add key="dotnet-experimental" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json" />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
  </packageSources>
</configuration>

ILCompilerの追加

> dotnet add package Microsoft.DotNet.ILCompiler -v 7.0.0-*

FibonacciVB.vbproj にItemGroup要素にMicrosoft.DotNet.ILCompilerが追加されました。

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <RootNamespace>FibonacciVB</RootNamespace>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.DotNet.ILCompiler" Version="7.0.0-*" />
  </ItemGroup>

</Project>

プログラムの修正

HelloWorldのままなのでプログラムを書き換えます。

Program.vb
Imports System

Module Program
    Sub Main(args As String())
        Console.WriteLine("Hello World!")
    End Sub
End Module

フィボナッチ数列にプログラムを書き換えます。
※C# 10.0 のように、namespace、Main、Import Systemを記述しないスクリプトライクのようには記述できません。

Program.vb
Imports System

Module VBModule

    Sub Main(args As String())
        Fibonacci_Iterative(10)
    End Sub

    Sub Fibonacci_Iterative(ByVal len As Integer)
        Dim a, b, c As Integer
        a = 0 : b  = 1 : c  = 0
        Console.Write("{0} {1}", a, b)

        For i As Integer = 2 To len - 1
            c = a + b
            Console.Write(" {0}", c)
            a = b
            b = c
        Next
    End Sub

End Module

image.png

NativeAOTによる発行

下記は発行のコマンドの説明になります。

> dotnet publish -r <RID> -c <Configuration>

RIDには、win-x64 or linux-x64 or osx-x64 を指定します。
残念ながらlinux-arm64がまだありませんので、Raspberry Pi 4用には出来ない。
Configurationには、 debug or release を指定します。

では、win-x64のreleaseで発行します。

> dotnet publish -r win-x64 -c release

FibonacciVB -> C:\WorkSpace\FibonacciVB\bin\release\net6.0\win-x64\publish\

image.png

FibonacciVB.exe でサイズが 4.18MiB あります。自分はWindows Terminal上でPowershellを使用しているので、先頭に"./"を付けて実行します。

> cd bin\release\net6.0\win-x64\native
> ./FibonacciVB.exe

0 1 1 2 3 5 8 13 21 34

イメージサイズ縮小

現在、FibonacciVB.exe でサイズが 4.18MiB あります。
PropertyGroup要素に幾つかオプションを追加してみます。
今回は実行速度より小さいコードサイズを優先にします。

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <RootNamespace>FibonacciVB</RootNamespace>
    <TargetFramework>net6.0</TargetFramework>

    <!-- https://github.com/dotnet/corert/blob/master/Documentation/using-corert/optimizing-corert.md -->
    <IlcOptimizationPreference>Size</IlcOptimizationPreference>
    <RootAllApplicationAssemblies>false</RootAllApplicationAssemblies>
    <IlcGenerateCompleteTypeMetadata>false</IlcGenerateCompleteTypeMetadata>
    <IlcGenerateStackTraceData>false</IlcGenerateStackTraceData>
    <IlcDisableReflection>true</IlcDisableReflection>
    <IlcFoldIdenticalMethodBodies>true</IlcFoldIdenticalMethodBodies>
    <IlcDisableUnhandledExceptionExperience>false</IlcDisableUnhandledExceptionExperience>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.DotNet.ILCompiler" Version="7.0.0-*" />
  </ItemGroup>

</Project>

再発行

> cd C:\WorkSpace\FibonacciVB
> dotnet publish -r win-x64 -c release

image.png

FibonacciVB.exe のサイズが 4.18 MiB → 1.13 MiB まで小さくなりました。
実行結果も問題ありません。

> cd bin\release\net6.0\win-x64\native
> ./FibonacciVB.exe

0 1 1 2 3 5 8 13 21 34

究極に小さく

下記サイトではあらゆるテクニックを駆使して、64MiBから8176バイトまで小さくしています。
Building a self-contained game in C# under 8 kilobytes

image.png

bflatの紹介

単純なアプリケーションの場合は bflat を使用すると良い結果が得られる可能性があります。
How to compile a .NET application to native code? - stackoverflow

bflatは、.NET実行可能ファイルを生成する「公式」C#コンパイラである。最も単純なアプリであっても、サイズが2MBから3MBの実行可能ファイルを生成します。
https://github.com/MichalStrehovsky/bflat

その他

Redditにて、NativeAOTの.NET 7での計画のスレッドがあります。
NativeAOT .NET 7 Plans
Is Native AOT on the roadmap?

WinFormsとNativeAOTについて、.NET 5の時なので.NET 6で対応されているかも。
Again WinForms and NativeAOT

最後に

無事に、.NET 6 + VB でも NativeAOTによりネイティブプログラムにすることが出来ました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0