C 라이브러리 내보내기
C 라이브러리 내보내기 (Exporting a C Library)
Zig의 대표적인 활용 사례 중 하나가 바로 C ABI로 라이브러리를 내보내서 다른 프로그래밍 언어에서 호출할 수 있게 만드는 거예요. 함수·변수·타입 앞에 export 키워드를 붙이면 그 대상이 라이브러리 API의 일부가 됩니다.
본문
export 키워드는 함수·변수·타입 앞에 붙여서 그 대상이 라이브러리의 공개 API가 되게 해요. 먼저 덧셈 함수를 내보내 볼게요.
export fn add(a: i32, b: i32) i32 {
return a + b;
}
이렇게 내보낸 함수를 정적 라이브러리로 만들려면 이렇게 해요.
$ zig build-lib mathtest.zig
공유 라이브러리(shared library)로 만들려면 -dynamic 옵션만 추가하면 돼요.
$ zig build-lib mathtest.zig -dynamic
이번엔 Zig Build System으로 똑같은 걸 만들어 볼게요. C 쪽에서 Zig 함수를 호출하는 테스트 프로그램을 준비합니다. mathtest.h 헤더는 Zig가 mathtest.zig로부터 자동 생성한 거예요.
// This header is generated by zig from mathtest.zig
#include "mathtest.h"
#include <stdio.h>
int main(int argc, char **argv) {
int32_t result = add(42, 1337);
printf("%d\n", result);
return 0;
}
이제 빌드 스크립트에서 라이브러리(addLibrary)와 테스트 실행 파일을 만들고, 실행 파일이 그 라이브러리를 링크하도록 연결해요.
const std = @import("std");
pub fn build(b: *std.Build) void {
const lib = b.addLibrary(.{
.linkage = .dynamic,
.name = "mathtest",
.root_module = b.createModule(.{
.root_source_file = b.path("mathtest.zig"),
}),
.version = .{ .major = 1, .minor = 0, .patch = 0 },
});
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.linkLibrary(lib);
b.default_step.dependOn(&exe.step);
const run_cmd = exe.run();
const test_step = b.step("test", "Test the program");
test_step.dependOn(&run_cmd.step);
}
zig build test로 빌드하고 테스트를 돌리면, Zig 쪽 add가 계산한 42 + 1337 = 1379가 출력돼요.
$ zig build test
1379
더 알아보기
- 함수·변수·타입을 라이브러리 API로 공개하는
export키워드에 대한 자세한 내용은 export에서 볼 수 있어요.