오브젝트 파일 섞기
오브젝트 파일 섞기 (Mixing Object Files)
Zig 오브젝트 파일은 C ABI를 따르는 다른 어떤 오브젝트 파일과도 섞어 쓸 수 있어요. 아래 예시를 따라가 볼게요.
본문
먼저 base64.zig에서 C 쪽에 노출할 함수를 export로 내보내요.
const base64 = @import("std").base64;
export fn decode_base_64(
dest_ptr: [*]u8,
dest_len: usize,
source_ptr: [*]const u8,
source_len: usize,
) usize {
const src = source_ptr[0..source_len];
const dest = dest_ptr[0..dest_len];
const base64_decoder = base64.standard.Decoder;
const decoded_size = base64_decoder.calcSizeForSlice(src) catch unreachable;
base64_decoder.decode(dest[0..decoded_size], src) catch unreachable;
return decoded_size;
}
이제 이 함수를 C에서 호출해요. 이때 base64.zig에서 직접 생성된 base64.h 헤더를 #include로 가져와서 씁니다.
// This header is generated by zig from base64.zig
#include "base64.h"
#include <string.h>
#include <stdio.h>
int main(int argc, char **argv) {
const char *encoded = "YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz";
char buf[200];
size_t len = decode_base_64(buf, 200, encoded, strlen(encoded));
buf[len] = 0;
puts(buf);
return 0;
}
두 파일을 한 바이너리로 묶는 건 빌드 스크립트에서 담당해요. Zig 오브젝트(addObject)를 만들고, C 소스와 함께 실행 파일에 합칩니다.
const std = @import("std");
pub fn build(b: *std.Build) void {
const obj = b.addObject(.{
.name = "base64",
.root_module = b.createModule(.{
.root_source_file = b.path("base64.zig"),
}),
});
const exe = b.addExecutable(.{
.name = "test",
.root_module = b.createModule(.{
.link_libc = true,
}),
});
exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
exe.root_module.addObject(obj);
b.installArtifact(exe);
}
빌드해서 실행하면, Zig 쪽에서 디코딩한 문자열이 그대로 출력돼요.
$ zig build
$ ./zig-out/bin/test
all your base are belong to us