📘

C言語のソースコードをZigに変換する機能を試す(その1)

2022/07/18に公開

zigのツールにCのソースコードをZigに変換する機能(zig translate-c)があるので、それを試してみました。
予想外に苦労したので、その1の記事はhello.c をhello.zigに変換してビルドして動作確認まで。

まずはHello, world!

hello.c
#include <stdio.h>

int main() 
{
	printf("Hello, world!\n");
}
$ zig cc hello.c 
$ ./a.out
Hello, world!
$ zig translate-c hello.c > hello.zig
hello.c:1:10: 'stdio.h' file not found

いろいろ試行錯誤してたどりついたものはこれ。
zig ccを実行したときにopenしているファイルをstraceコマンドで調べて、それと同じになるように-Iオプションを明示的に指定した。

$ zig translate-c \
-I /usr/local/zig-linux-aarch64-0.9.1/lib/libc/include/aarch64-linux-gnu \
-I /usr/local/zig-linux-aarch64-0.9.1/lib/libc/include/generic-glibc/ \
hello.c > hello.zig

CからZigに変換できた。

$ wc hello.zig
 1057  6531 63259 hello.zig

1000行を超えてる。インクルードヘッダにあるもの全部を変換しているので。

さっそくビルドしてみる。

$ zig build-exe hello.zig 
/usr/local/zig-linux-aarch64-0.9.1/lib/std/start.zig:556:17: error: expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'
                @compileError(bad_main_ret);
                ^

hello.zig を手で修正。

hello.zig
...

pub export fn main() c_int {
    _ = printf("Hello, world!\n");
    return 0;
}

...

main()の型を以下のように変更。

pub export fn main() u8 {
    _ = printf("Hello, world!\n");
    return 0;
}
$ zig build-exe hello.zig 
ld.lld: error: undefined symbol: printf
>>> referenced by hello.zig:157 (/autofs/usbssd1/koba/work/zig/hello/hello.zig:157)
>>>               zig-cache/o/f5b23074efffa90c73ace48f9f903a31/hello.o:(main)
error: LLDReportedFailure

今度はリンクエラー。

$ zig build-exe -lc hello.zig

できた!

$ ls -lt
total 832
-rwxrwxr-x 1 koba koba 561448  7月 18 12:55 hello
-rw-rw-r-- 1 koba koba  29729  7月 18 12:54 hello.zig
-rw-rw-r-- 1 koba koba  29744  7月 18 12:47 hello.zig~
-rw-rw-r-- 1 koba koba     75  7月 18 12:47 hello.c
drwxr-xr-x 5 koba koba   4096  7月 18 12:45 zig-cache
-rw-rw-r-- 1 koba koba 204186  7月 18 12:27 st.log
-rwxrwxr-x 1 koba koba   3784  7月 18 12:18 a.out
$ ./hello 
Hello, world!

動いた。

$ file ./hello
./hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 2.0.0, with debug_info, not stripped
$ ldd ./hello
	linux-vdso.so.1 (0x0000ffff8cb50000)
	libpthread.so.0 => /lib/aarch64-linux-gnu/libpthread.so.0 (0x0000ffff8cad2000)
	libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ffff8c95f000)
	/lib/ld-linux-aarch64.so.1 (0x0000ffff8cb20000)

まとめ

zig translate-c には明示的にインクルードファイルのディレクトリを指定する必要がある。

$ zig translate-c -I /usr/local/zig-linux-aarch64-0.9.1/lib/libc/include/aarch64-linux-gnu -I /usr/local/zig-linux-aarch64-0.9.1/lib/libc/include/generic-glibc/ hello.c > hello.zig

main()の戻り値の型はZigの仕様に従うように修正する

c_int -> u8

標準Cライブラリのリンクも明示的に -lc をつける

$ zig build-exe -lc hello.zig

関連

https://zenn.dev/tetsu_koba/articles/421198dc669f19

Discussion