Closed7

Alire で Ada を始めてみる

uasiuasi

Ada

Ada といえば軍や航空産業でかつて使われていた古の言語のイメージだったが、最近 r/programming あたりでちょこちょこ話題を見かけるようになった。大手 Ada ベンダの AdaCore が Ada 用の Visual Studio Code 拡張や Language Protocol Server やパッケージマネージャを次々作って今の流行に追いつこうとしているらしい。

言語自体は厳格で多機能だというから、開発体験さえよければ Rust や Go の代わりとして使えるかもしれない。ちょっと見てみる。

uasiuasi

Alire とは

Alire はパッケージ化した Ada のライブラリをインストールできるパッケージマネージャ。 Rust の Cargo にガッツリ影響を受けた設計のようだ。メタデータとともにパッケージ化されたコード一式を crate と呼ぶのも影響のひとつだろう。 Crate のインデックスには現時点で188個登録されている。

Alire はコンパイラツールチェインもインストールしてくれる。 Rust でいう rustup の機能も備えているようだ。

uasiuasi

Alire でツールチェインをインストールする

Alire のリリースページ から alr バイナリをダウンロードして PATH の通ったところに置く。 alr toolchain --select を実行すると GNAT 11.2.1 をインストールできる。

Welcome to the toolchain selection assistant

In this assistant you can set up the default toolchain to be used with any crate
that does not specify its own top-level dependency on a version of gnat or
gprbuild.

If you choose "None", Alire will use whatever version is found in the
environment.

ⓘ Currently configured: gnat_native=11.2.1

Please select the gnat version for use with this configuration
  1. gnat_native=11.2.1
  2. None
  3. gnat_arm_elf=11.2.1
  4. gnat_riscv64_elf=11.2.1
  5. gnat_arm_elf=10.3.1
  6. gnat_native=10.3.1
  7. gnat_riscv64_elf=10.3.1
Enter your choice index (first is default):
> 1
ⓘ Selected tool version gnat_native=11.2.1

ⓘ Choices for the following tool are narrowed down to releases compatible with just selected gnat_native=11.2.1

ⓘ Currently configured: gprbuild=21.0.1

Please select the gprbuild version for use with this configuration
  1. gprbuild=21.0.1
  2. None
Enter your choice index (first is default):
>
ⓘ Selected tool version gprbuild=21.0.1
uasiuasi

Alire で新規プロジェクトを作る

alr init (--bin|--lib) $name で crate の雛形を作れる。

% alr init --bin hello_ada
✓ hello_ada initialized successfully.

プロジェクトの構成はこんな感じ。

% exa -T hello_ada
hello_ada
├── alire
│  └── alire.lock
├── alire.toml
├── config
│  └── hello_ada_config.gpr
├── hello_ada.gpr
└── src
   └── hello_ada.adb

alire.toml はマニフェストファイル。 Crate の名前や説明、作者名、それに依存関係などが書いてある。

alire/alire.lock はロックファイル。他の言語のパッケージマネージャと違ってロックファイルはコミットしない(ことに最近なった[1])ようだ。

hello_ada.gpr は GNAT Project Manager[2] がビルドで使うファイル。中にはコンパイルフラグなどがずらずら書いてある。 config/hello_ada_config.gpr をインポートしている。こちらにはパッケージのバージョンが書かれているだけ。基本的に後者だけいじればよさそうだ。

コードは src/hello_ada.adb に書いてある。

脚注
  1. Move the lockfile inside $crate/alire by mosteo · Pull Request #789 · alire-project/alire ↩︎

  2. 2. GNAT Project Manager — GPR Tools User's Guide 23.0w documentation ↩︎

uasiuasi

Hello, world を書く

まず alr のソースコード をざっと見て流儀を把握する。 https://github.com/alire-project/alire/tree/master/src/alr

.adb は Ada の Body のことでパッケージ実装を書くファイル。 .ads は Ada の Specification でいわゆるヘッダファイル。細かいことは learn.adacore.com に書いてある。

https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Developer/chapters/02_Perspective.html#compilation-unit-structure

Alr.Utils.Temp_File パッケージのコードは alr-utils-temp_file.ad{b,s} にある。ファイル名はパッケージ名を lowercase にしてドットをハイフンに変えた名前にすればよさそう。たぶん慣習でしかないが、守らないとどこかで警告が出た。

コーディングスタイルのアタリも付けておく。

  • 予約語は case-insensitive だが小文字にする慣習らしい
  • パッケージ名、関数名、変数名などはすべて Ada_Case。入力は面倒だが慣れると見やすい
  • インデントは世にも珍しい3スペース
  • 関数名とカッコの間にスペース

さて、記憶を頼りに Hello, world を書く。

with Ada.Text_IO;

procedure Hello_Ada is
begin
   Ada.Text_IO.Put_Line ("Hello, Ada!");
end Hello_Ada;

で、ビルド。

% alr build
Setup
   [mkdir]        object directory for project Hello_Ada
   [mkdir]        exec directory for project Hello_Ada
Compile
   [Ada]          hello_ada.adb
Bind
   [gprbind]      hello_ada.bexch
   [Ada]          hello_ada.ali
Link
   [link]         hello_ada.adb

できた。実行する。

% alr run
gprbuild: "hello_ada" up to date
Hello, Ada!

動いた。 gprbuild: "hello_ada" up to date はコンソールだと灰色で出力されていて標準出力と見分けがつく。

実行ファイルは bin/hello_ada にあるので直接実行してもいい。

alr run は必要なら自動でビルドするので alr build を手で打つ必要はない。

uasiuasi

Ada に慣れる

メッセージ出力を別のプロシージャに切り出してみようか。

with Ada.Text_IO;

procedure Say_Hello is
begin
   Ada.Text_IO.Put_Line ("Hello, Ada!");
end Say_Hello;

procedure Hello_Ada is
begin
   Say_Hello;
end Hello_Ada;

ビルド。

% alr build
Compile
   [Ada]          hello_ada.adb
hello_ada.adb:3:12: warning: file name does not match unit name, should be "say_hello.adb"
hello_ada.adb:8:01: end of file expected, file can have only one compilation unit

   compilation of hello_ada.adb failed

gprbuild: *** compilation phase failed
error: Command ["gprbuild", "-gnatwU", "-j0", "-p", "-P", "hello_ada.gpr"] exited with code 4
error: Compilation failed.

動かない。ファイル名を say_hello.adb にするよう警告が出ている。これはファイル内の1つ目のプロシージャに名前を合わせろということか。それにファイルにはひとつのコンパイル単位しか書けないとエラーが出ている。

プロシージャの宣言ブロックで別のプロシージャを宣言できたはず。ネストしてみる。

with Ada.Text_IO;

procedure Hello_Ada is

  procedure Say_Hello is
  begin
     Ada.Text_IO.Put_Line ("Hello, Ada!");
  end Say_Hello;

begin
   Say_Hello;
end Hello_Ada;
% alr run
gprbuild: "hello_ada" up to date
Hello, Ada!

動いた。

uasiuasi

Ada で日本語を使う

Ada の標準の文字列型は Latin-1 エンコードのようだ。

https://two-wrongs.com/unicode-strings-in-ada-2012
https://www.reddit.com/r/ada/comments/pnokh9/comment/hct0hwc/?utm_source=share&utm_medium=web2x&context=3

このへんの記事を読んだ。 UTF-8 の扱いは何やら面倒そう。とりあえず VSS という文字列ライブラリを入れてみる。 alr with $crate_name で crate をインストールできる。

-> % alr with vss
Requested changes:

   ✓ vss ^22.0.0-20210830 (add)

Changes to dependency solution:

   +♼ gnat 11.2.1          (new,installed,gnat_native,indirect)
   +  vss  22.0.0-20210830 (new)

Do you want to proceed?
[Y] Yes  [N] No  (default is Yes)
Using default: Yes
ⓘ Deploying release vss=22.0.0-20210830...

alire.toml に依存関係の設定が足された。

diff --git a/alire.toml b/alire.toml
index ae408dc..155d6f5 100644
--- a/alire.toml
+++ b/alire.toml
@@ -7,3 +7,5 @@ maintainers = ["(snip)"]
 maintainers-logins = ["(snip)"]

 executables = ["hello_ada"]
+[[depends-on]]  # Added by alr
+vss = "^22.0.0-20210830"  # Added by alr

コードで UTF-8 文字列を使ってみる。

with Ada.Text_IO;
with Ada.Strings.UTF_Encoding;
with VSS.Strings;

procedure Hello_Ada is

   use Ada.Strings.UTF_Encoding;

   Hello : UTF_8_String := "こんにちは";
   Name : UTF_8_String := "エイダ";

   procedure Say_Hello is
   begin
      declare
         Message : UTF_8_String := Hello & Name;
      begin
         Ada.Text_IO.Put_Line (Message);
      end;
   end Say_Hello;

begin
   Say_Hello;
end Hello_Ada;
% alr run
gprbuild: "hello_ada" up to date
こんにちはエイダ

動いた……が VSS を使ってないな? 文字列操作が必要なときに活躍するんだろう。

このスクラップは2024/01/04にクローズされました