Alire で Ada を始めてみる
Ada
Ada といえば軍や航空産業でかつて使われていた古の言語のイメージだったが、最近 r/programming あたりでちょこちょこ話題を見かけるようになった。大手 Ada ベンダの AdaCore が Ada 用の Visual Studio Code 拡張や Language Protocol Server やパッケージマネージャを次々作って今の流行に追いつこうとしているらしい。
言語自体は厳格で多機能だというから、開発体験さえよければ Rust や Go の代わりとして使えるかもしれない。ちょっと見てみる。
Alire とは
Alire はパッケージ化した Ada のライブラリをインストールできるパッケージマネージャ。 Rust の Cargo にガッツリ影響を受けた設計のようだ。メタデータとともにパッケージ化されたコード一式を crate と呼ぶのも影響のひとつだろう。 Crate のインデックスには現時点で188個登録されている。
Alire はコンパイラツールチェインもインストールしてくれる。 Rust でいう rustup
の機能も備えているようだ。
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
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 に書いてある。
Hello, world を書く
まず alr のソースコード をざっと見て流儀を把握する。 https://github.com/alire-project/alire/tree/master/src/alr
.adb は Ada の Body のことでパッケージ実装を書くファイル。 .ads は Ada の Specification でいわゆるヘッダファイル。細かいことは learn.adacore.com に書いてある。
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
を手で打つ必要はない。
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!
動いた。
Ada で日本語を使う
Ada の標準の文字列型は Latin-1 エンコードのようだ。
このへんの記事を読んだ。 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 を使ってないな? 文字列操作が必要なときに活躍するんだろう。