zigでのとりあえずC言語との連携的な方法が断片的に分かったので、その方法を記載する。
実行ファイルでCを読ませたい場合、exe
定数にて*Compile
がaddIncludePath()
、addCSourceFiles()
、linkLibC()
メソッドを持ってるから、それを呼べば良いらしい。
pub fn build(b: *std.Build) void {
//...
const exe = b.addExecutable(.{
.name = "zig-test",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
exe.addIncludePath(.{ .path = "src" });
exe.addCSourceFiles(.{ .files = &.{
"src/util.c",
} });
exe.linkLibC();
//...
}
以下のようなCヘッダがあったとして、
#pragma once
typedef struct Value
{
int value;
int (*get)(struct Value *);
void (*add)(struct Value *, int);
void (*sub)(struct Value *, int);
void (*print)(struct Value *);
} Value;
Value createValue(int v);
int getValue(struct Value *self);
void addValue(struct Value *self, int v);
void subValue(struct Value *self, int v);
void printValue(struct Value *self);
定義ファイルはこんな感じにしておいた場合、
#include <stdio.h>
#include "util.h"
Value createValue(int v)
{
Value value;
value.value = v;
value.get = getValue;
value.add = addValue;
value.sub = subValue;
value.print = printValue;
return value;
}
int getValue(Value *self)
{
return self->value;
}
void addValue(Value *self, int v)
{
self->value += v;
}
void subValue(Value *self, int v)
{
self->value -= v;
}
void printValue(Value *self)
{
printf("Value: %d\n", self->value);
}
以下みたいな感じにしたら動いた
const std = @import("std");
const util = @cImport(@cInclude("util.h"));
pub fn main() !void {
var value = util.createValue(100);
if (value.get) |get| {
std.debug.print("Value From C: {}\n", .{get(&value)});
}
if (value.add) |add| {
add(&value, 100);
}
if (value.sub) |sub| {
sub(&value, 50);
}
if (value.print) |print| {
print(&value);
}
}
実行結果は↓
とりあえずこういった設定だとzig build run
じゃなきゃだめみたい。
あまり細かいところは分かっていない…
vscode ➜ /workspaces/zig-test $ zig build run
Value From C: 100
Value: 150
とはいえ、zig側で固く型検証してくれるのは良いかも。慣れればC側の技術を上手く使ったり、逆を使ったりして出来るんだろうね。
とりあえず、Cのプログラムがそのまま確かに動いちゃう。zigってこのまま混ぜ混ぜして組み込みデバイスやWebAssemblyにも持っていける(かもしれない?)らしいから、そう思うと可能性は広がるね。Uberがやっていると言うPC向け汎用コンパイラとしての使い方は中々アリかも。
ファイルサイズが超コンパクト
おそらくzigがすごいのはこれじゃないでしょうか。恐らくRustで作成するより更に小さいです。普通のCとどっこいどっこいじゃないかと。それでパフォーマンスが良い、のがこの言語の1つの魅力かと。
以下は上のプログラムのバイナリの結果です。
正直Goの極厚サイズでも気にしないケースなんて多いわけで、Rustレベルで十分でしょ、と思うことが大半だと思いますが、wasm (wasi)もちゃんと動きました。
.rwxr-xr-x 7.6k xxxxx 2 9月 xxxxx zig-test
.rwxr--r-- 29k xxxxx 2 9月 xxxxx zig-test.wasm
ちなみに以下のコマンドを使った。(オプションをよく分かってないのでメモで)
zig build -Dtarget wasm32-wasi -Doptimize=ReleaseSmall