Zenを使ってみた

 Zenのv0.8がリリースされました。

 さっそく、触ってみました。

 次のWebページからZenをダウンロードします。

https://www.zen-lang.org/ja-JP/download/

 ダウンロードしたファイルを解凍して、PATHを設定します。

 これで使う環境が整いました。

$ zen-linux-x86_64-0.8.20191124+552247019.tar.xz
$ export PATH=${PATH}:<INSTALL_DIR>/zen-linux-x86_64-0.8.20191124+552247019/

Hello World!

 まずはHello World!からやってみます。

 この辺りはZenのチュートリアルに載っているので詳しくはチュートリアルを見てくださいませ。

 最初にビルド環境を整えます。

$ zen init-exe
Created build.zen
Created src/main.zen

Next, try `zen build --help` or `zen build run`

 本当にビルドできる環境なのか、ビルドして実行してみます。

$ zen build run
Congratulations on your first step to writing perfect software in Zen.

 問題ないので単体でビルドしてみます。

$ zen build-exe src/main.zen 

 これも問題ないですね。

 main.zenのmain関数を次のように修正してHello World!が出来るようにしてビルドします。

    // 標準出力を取得できない環境では、エラーが発生してプログラムが停止します。
    const stdout = try std.fs.getStdOut();
    // 標準出力への表示に失敗すると、エラーが発生してプログラムが停止します。
    try stdout.write("Hello, world!\n");

 まぁ、特に問題ないでしょう。

 main.zenは次のとおりです。

const std = @import("std");

pub fn main() anyerror!void {
    // 標準出力を取得できない環境では、エラーが発生してプログラムが停止します。
    const stdout = try std.fs.getStdOut();
    // 標準出力への表示に失敗すると、エラーが発生してプログラムが停止します。
    try stdout.write("Hello, world!\n");
}

ZenからCを呼び出す

 次にZenからCを呼び出せるか確認しました。

 次のようにadd.hを用意します。

int add(int a, int b);

 次のようにadd.cを用意します。

int add(int a, int b)
{
    return a + b;
}

 ZenでCソースコードをコンパイルしてみます。

$ zen cc -c add.c

 add.oができるので中身を確認してみます。

$ file add.o
add.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

 まぁ、特に問題はありません。

 次にライブラリにします。

$ zen build-lib --object add.o --name add

 これも問題ありません。

$ file libadd.a 
libadd.a: current ar archive

 本題はgccでコンパイルしたCソースコードをZenから使えるかを試したかったのでadd.cを次のようにライブラリにしました。

$ gcc -c -o add.o add.c
$ ar rcs libadd.a add.o

 Zenでインポートするためのadd.hからadd_h.zenを作成します。

$ zen translate-c add.h > add_h.zen

 Zenのmain.zenでadd.cのadd関数を呼び出されるようにして、次のようにビルドしました。

$ zen build-exe main.zen -ladd -L.

 特に問題なく使えました。

$ ./main
Result: 3

 main.zenは次のとおりです。

const std = @import("std");

// add関数が含まれたヘッダーファイルをインポートする
const c = @import("add_h.zen");

pub fn main() anyerror!void {
    // 標準出力を取得できない環境では、エラーが発生してプログラムが停止します。
    const stdout = try std.fs.getStdOut();

    var z: i32 = 0;

    z = c.add(1, 2);

    // 標準出力への表示に失敗すると、エラーが発生してプログラムが停止します。
    try std.fs.write.print(stdout,"Result: {}\n", z);
}

CからZenを呼び出す。

 次は逆にCからZenを呼び出す確認です。

 次のようにZenでadd関数を作成しました。

export fn add(a: i32, b: i32)
i32
{
  var c: i32 = 0;

  c = a + b;

  return c;
}

 ZenソースコードをCから呼び出すライブラリを作成するには次のようにビルドします。

$ zen build-lib add.zen --bundle-compiler-rt -fPIC

 clangだと、-fPCIは必要ありません。

 次の3つのファイルが生成されるのでこれをCから呼び出します。

 main.cは次のとおりです。

#include <stdio.h>
#include "add.h"

int main()
{
    int z;

    z = add( 1, 2 );

    printf("Result: %d\n", z);

    return 0;
}

 Cソースコードを次のようにビルドします。

$ gcc -o main main.c -ladd -L.

 結果は問題なく使えました。

$ ./main 
Result: 3